33

フィールドのタイプに基づいてフィールドの 1 つに異なる名前が付けられるように、オブジェクトをシリアライズしたいと考えています。例えば:

public class Response {
    private Status status;
    private String error;
    private Object data;
        [ getters, setters ]
    }

ここでは、状況に応じて異なるタイプを含むフィールドが常に呼び出されるのではなく、フィールドdataを次のようにシリアル化する必要があります。data.getClass.getName()data

Jackson を使用してそのようなトリックを達成するにはどうすればよいでしょうか?

4

4 に答える 4

38

カスタムを使用しますJsonSerializer

public class Response {
  private String status;
  private String error;

  @JsonProperty("p")
  @JsonSerialize(using = CustomSerializer.class)
  private Object data;

  // ...
}

public class CustomSerializer extends JsonSerializer<Object> {
  public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
    jgen.writeStartObject();
    jgen.writeObjectField(value.getClass().getName(), value);
    jgen.writeEndObject();
  }
}

次に、次の2つのオブジェクトをシリアル化するとします。

public static void main(String... args) throws Exception {
  ObjectMapper mapper = new ObjectMapper();
  Response r1 = new Response("Error", "Some error", 20);
  System.out.println(mapper.writeValueAsString(r1));
  Response r2 = new Response("Error", "Some error", "some string");
  System.out.println(mapper.writeValueAsString(r2));
}

最初のものは印刷されます:

{"status":"Error","error":"Some error","p":{"java.lang.Integer":20}}

そして2番目のもの:

{"status":"Error","error":"Some error","p":{"java.lang.String":"some string"}}

pラッパーオブジェクトの名前は、単にpレースホルダーとして機能するため、使用しました。これを削除する場合は、クラス全体JsonSerializer<Response>のカスタムシリアライザーを作成する必要があります。

于 2012-08-26T23:10:20.203 に答える
5

私自身の解決策。

@Data
@EqualsAndHashCode
@ToString
@JsonSerialize(using = ElementsListBean.CustomSerializer.class)
public class ElementsListBean<T> {

    public ElementsListBean()
    {
    }

    public ElementsListBean(final String fieldName, final List<T> elements)
    {
        this.fieldName = fieldName;
        this.elements = elements;
    }

    private String fieldName;

    private List<T> elements;

    public int length()
    {
        return (this.elements != null) ? this.elements.size() : 0;
    }

    private static class CustomSerializer extends JsonSerializer<Object> {
        public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException,
                JsonProcessingException
        {
            if (value instanceof ElementsListBean) {
                final ElementsListBean<?> o = (ElementsListBean<?>) value;
                jgen.writeStartObject();
                jgen.writeArrayFieldStart(o.getFieldName());
                for (Object e : o.getElements()) {
                    jgen.writeObject(e);
                }
                jgen.writeEndArray();
                jgen.writeNumberField("length", o.length());
                jgen.writeEndObject();
            }
        }
    }
}
于 2012-09-06T12:32:05.687 に答える
4

アノテーションを使用するJsonTypeInfoと、Jackson にそのことを正確に伝えることができ、カスタム シリアライザーを記述する必要はありません。この情報を含めるにはさまざまな方法がありますが、特定の質問に対しては と を使用As.WRAPPER_OBJECTId.CLASSます。例えば:

public static class Response {
    private Status status;
    private String error;
    @JsonTypeInfo(include = As.WRAPPER_OBJECT, use = Id.CLASS)
    private Object data;
}

ただし、これは String や Integer などのプリミティブ型では機能しません。プリミティブは JSON でネイティブに表現され、Jackson はそれらの処理方法を知っているため、プリミティブの情報は必要ありません。注釈を使用することの追加のボーナスは、デシリアライズが必要になった場合に無料で入手できることです。次に例を示します。

public static void main(String[] args) throws Exception {
    ObjectMapper mapper = new ObjectMapper();
    Response r1 = new Response("Status", "An error", "some data");
    Response r2 = new Response("Status", "An error", 10);
    Response r3 = new Response("Status", "An error", new MyClass("data"));
    System.out.println(mapper.writeValueAsString(r1));
    System.out.println(mapper.writeValueAsString(r2));
    System.out.println(mapper.writeValueAsString(r3));
}

@JsonAutoDetect(fieldVisibility=Visibility.ANY)
public static class MyClass{
    private String data;
    public MyClass(String data) {
        this.data = data;
    }
}

そして結果:

{"status":"Status","error":"An error","data":"some data"}
{"status":"Status","error":"An error","data":10}
{"status":"Status","error":"An error","data":{"some.package.MyClass":{"data":"data"}}}
于 2012-08-27T16:36:26.730 に答える