Java 具有对象类型的 Jackson JSON 列表

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22917324/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 18:59:13  来源:igfitidea点击:

Hymanson JSON List with Object Type

javajsonserializationtypesHymanson

提问by raoulsson

I have to serialize JSON from a list of Objects. The resulting JSON has to look like this:

我必须从对象列表中序列化 JSON。生成的 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
}

采纳答案by Sotirios Delimanolis

There's no built-in way to do this. You'll have to write your own JsonSerializer. Something like

没有内置的方法可以做到这一点。您必须编写自己的JsonSerializer. 就像是

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 modelsfield 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.

如果您同时对其进行序列化和反序列化,则还需要一个自定义的反序列化器。

回答by coderatchet

This is an oldish question, But there is an arguably more idiomatic way of implementing this (I'm using Hymanson-databind:2.8.8):

这是一个古老的问题,但有一种可以说是更惯用的实现方式(我正在使用Hymanson-databind:2.8.8):

Define a ModelSerializer(That extends StdSerializeras recommended by Hymanson) that prints your model how you like and use the @JsonSerialize(contentUsing = ...)over your collection type:

定义一个ModelSerializerStdSerializer按照Hyman逊的建议扩展),以您喜欢的方式打印模型并使用@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 Lists of models but may apply this to Collections, Sets, Native []s and even the values of Maps.

现在,您不仅限于List模型的 s,还可以将其应用于Collections、Sets、Native []s 甚至 s 的值Map

回答by Decoded

Another approachis using StdConverterclass. Here is a working (abbreviated) example:

另一种方法是使用StdConverter类。这是一个工作(缩写)示例:

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

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

import com.fasterxml.Hymanson.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 Hymanson "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.Hymanson.core.JsonParseException;
import com.fasterxml.Hymanson.core.type.TypeReference;
import com.fasterxml.Hymanson.databind.JsonMappingException;
import com.fasterxml.Hymanson.databind.ObjectMapper;
import com.fasterxml.Hymanson.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.

我喜欢这个因为它让你可以分别控制序列化和反序列化。