简体   繁体   English

具有对象类型的 Jackson JSON 列表

[英]Jackson JSON List with Object Type

I have to serialize JSON from a list of Objects.我必须从对象列表中序列化 JSON。 The resulting JSON has to look like this:生成的 JSON 必须如下所示:

{
    "status": "success",
    "models": [
        {
            "model": {
                "id": 23,
                "color": "red"
            }
        },
        {
            "model": {
                "id": 24,
                "color": "green"
            }
        }
    ]
}

I am missing the type/key "model" when I simply serialize this:当我简单地序列化它时,我缺少类型/键“模型”:

List<Model> list = new ArrayList<Model>(); // add some new Model(...)
Response r = new Response("success", list); // Response has field "models"

Instead I just get this:相反,我只是得到这个:

{
    "status": "success",
    "models": [
        {
            "id": 23,
            "color": "red"
        },
        {
            "id": 24,
            "color": "green"
        }
    ]
}

How can I add "model" for each object without having to write a silly wrapper class with a property "model"?如何为每个对象添加“模型”而不必编写带有属性“模型”的愚蠢包装类?

My classes look like this:我的课程是这样的:

public class Response {
    private String status;
    private List<Model> models;
    // getters / setters
}

public class Model {
    private Integer id;
    private String color;
    // getters / setters
}

There's no built-in way to do this.没有内置的方法可以做到这一点。 You'll have to write your own JsonSerializer .您必须编写自己的JsonSerializer Something like就像是

class ModelSerializer extends JsonSerializer<List<Model>> {

    @Override
    public void serialize(List<Model> value, JsonGenerator jgen,
            SerializerProvider provider) throws IOException {
        jgen.writeStartArray();
        for (Model model : value) {
            jgen.writeStartObject();
            jgen.writeObjectField("model", model);
            jgen.writeEndObject();    
        }
        jgen.writeEndArray();
    }

}

and then annotate the models field so that it uses it然后注释models字段,以便它使用它

@JsonSerialize(using = ModelSerializer.class)
private List<Model> models;

This would serialize as这将序列化为

{
    "status": "success",
    "models": [
        {
            "model": {
                "id": 1,
                "color": "red"
            }
        },
        {
            "model": {
                "id": 2,
                "color": "green"
            }
        }
    ]
}

If you're both serializing and deserializing this, you'll need a custom deserializer as well.如果您同时对其进行序列化和反序列化,则还需要一个自定义的反序列化器。

This is an oldish question, But there is an arguably more idiomatic way of implementing this (I'm using jackson-databind:2.8.8 ):这是一个古老的问题,但有一种可以说是更惯用的实现方式(我使用的是jackson-databind:2.8.8 ):

Define a ModelSerializer (That extends StdSerializer as recommended by Jackson) that prints your model how you like and use the @JsonSerialize(contentUsing = ...) over your collection type:定义一个ModelSerializer (它扩展了 Jackson 推荐的StdSerializer ),它打印您喜欢的模型并在您的集合类型上使用@JsonSerialize(contentUsing = ...)

class ModelSerializer extends StdSerializer<Model> {

    public ModelSerializer(){this(null);}
    public ModelSerializer(Class<Model> t){super(t);} // sets `handledType` to the provided class

    @Override
    public void serialize(List<Model> value, JsonGenerator jgen,
            SerializerProvider provider) throws IOException,
            JsonProcessingException {
        jgen.writeStartObject();
        jgen.writeObjectField("model", value);
        jgen.writeEndObject();
    }
}

Meanwhile, in another file:同时,在另一个文件中:

class SomethingWithModels {
    // ...
    @JsonSerialize(contentUsing = ModelSerializer.class)
    private Collection<Model> models;
    // ...
}

Now you aren't bound to just List s of models but may apply this to Collection s, Set s, Native [] s and even the values of Map s.现在,您不仅限于模型的List ,还可以将其应用于CollectionSet 、 Native []甚至Map的值。

Another approach is using StdConverter class.另一种方法是使用StdConverter类。 Here is a working (abbreviated) example:这是一个工作(缩写)示例:

// MyParentObject.java
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;

public class MyParentObject {
  @JsonSerialize(converter = ChildListToString.class)
  @JsonDeserialize(converter = StringToChildList.class)
  @JsonProperty
  public List<AChildObject> myChildren;
}
// ChildListToString.java

import com.fasterxml.jackson.databind.util.StdConverter;

import java.util.List;
import java.util.stream.Collectors;

public class ChildListToString extends StdConverter<List<AChildObject>, String> {
  @Override
  public String convert(List<IntakeModuleUrn> value) {
    // this is just as effective as using Jackson "write array"
    // Try-Catch omitted for brevity
    StringBuilder builder = new StringBuilder("[");
    value.stream().map(value -> new ObjectMapper().writeValue(value)).forEach(urnStr -> {
      if(builder.length() > 1) {
        builder.append(", ");
      }

      builder.append("\"").append(urnStr).append("\"");
    });

    builder.append("]");

    return builder.toString();
  }
}
// StringToChildList.java

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.util.StdConverter;


import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

public class StringToChildList extends StdConverter<String, List<AChildObject>> {

  @Override
  public List<AChildObject> convert(String value) {
    // try - catch omitted here for brevity
      List<String> strings = new ObjectMapper().readValue(value, new TypeReference<List<String>>() {});
      return strings.stream()
          .map(string -> {
            return new ObjectMapper().readValue(string, AChildObject.class)
          }).collect(Collectors.toList());

  }
}

I like this because it gives you control of serialization and deserialization separately.我喜欢这个因为它让你可以分别控制序列化和反序列化。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM