[英]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
,还可以将其应用于Collection
、 Set
、 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.