Java + Jackson:如何序列化包含其他对象的数组/列表的对象

时间:2017-02-07 10:19:04

标签: java json serialization jackson

我试图在输入参数的基础上动态生成以下json,即(内容' s版本,内容ID列表)

{
  "query": {
    "bool": {
       "must": [
        {
          "term": {
            "version": {
              "value": "published"
            }
          }
       },
       {
          "terms": {
            "contentId": [
             "contentId-123",
             "contentId-456"
            ]
          }
        }
      ]
    }
  }
}

上面的json是弹性搜索删除请求的查询主体。 上面提到的versioncontentId是内容对象或数据模型的实际字段/属性。

我在序列化对象时遇到此异常:

com.fasterxml.jackson.core.JsonGenerationException: Can not start an object, expecting field name
    at com.fasterxml.jackson.core.JsonGenerator._reportError(JsonGenerator.java:1886)
    at com.fasterxml.jackson.core.json.WriterBasedJsonGenerator._verifyPrettyValueWrite(WriterBasedJsonGenerator.java:832)
    at com.fasterxml.jackson.core.json.WriterBasedJsonGenerator._verifyValueWrite(WriterBasedJsonGenerator.java:797)
    at com.fasterxml.jackson.core.json.WriterBasedJsonGenerator.writeStartObject(WriterBasedJsonGenerator.java:268)
    at com.cdk.dmg.services.sitecontent.util.ConstantsTest$DeleteQuerySerializer.serialize(Test.java:200)
    at com.cdk.dmg.services.sitecontent.util.ConstantsTest$DeleteQuerySerializer.serialize(Test.java:183)
    at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:292)
    at com.fasterxml.jackson.databind.ObjectWriter$Prefetch.serialize(ObjectWriter.java:1419)
    at com.fasterxml.jackson.databind.ObjectWriter._configAndWriteValue(ObjectWriter.java:1147)
    at com.fasterxml.jackson.databind.ObjectWriter.writeValueAsString(ObjectWriter.java:1020)

这是我的代码:

class SearchParam {
    boolean isMultivalued;
    String fieldName;
    String value;
    List<String> values;

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder("SearchParam{");
        sb.append("isMultivalued=").append(isMultivalued);
        sb.append(", fieldName='").append(fieldName).append('\'');
        sb.append(", value='").append(value).append('\'');
        sb.append(", values=").append(values);
        sb.append('}');
        return sb.toString();
    }
}

class DeleteQuery {
    List<SearchParam> mustParams;
}

class DeleteQuerySerializer extends StdSerializer<DeleteQuery> {

    protected DeleteQuerySerializer(Class<DeleteQuery> t) {
        super(t);
    }

    public DeleteQuerySerializer() {
        this(null);
    }

    @Override
    public void serialize(DeleteQuery value, JsonGenerator jsonGen, SerializerProvider provider) throws IOException {
        jsonGen.writeStartObject();
        jsonGen.writeObjectFieldStart("query");
        jsonGen.writeObjectFieldStart("bool");
        jsonGen.writeArrayFieldStart("must");
        for (SearchParam param : value.mustParams) {
            jsonGen.writeObject(param);
        }
        jsonGen.writeEndObject();
    }
}

class SearchParamSerializer extends StdSerializer<SearchParam> {

    protected SearchParamSerializer(Class<SearchParam> t) {
        super(t);
    }

    protected SearchParamSerializer() {
        this(null);
    }

    @Override
    public void serialize(SearchParam value, JsonGenerator jsonGen, SerializerProvider provider) throws IOException, JsonGenerationException {
        jsonGen.writeStartObject();
        if (value.isMultivalued) {
            jsonGen.writeObjectFieldStart("terms");
            jsonGen.writeArrayFieldStart(value.fieldName);
            for (String v : value.values) {
                jsonGen.writeString(v);
            }
            jsonGen.writeEndArray();
        } else {
            jsonGen.writeObjectFieldStart("term");
            jsonGen.writeObjectFieldStart(value.fieldName);
            jsonGen.writeStringField("value", value.value);
        }
        jsonGen.writeEndObject();
    }
}

@Test
public void dummyTest() throws JsonProcessingException {

    SearchParam versionParam = new SearchParam();
    versionParam.fieldName = "version";
    versionParam.isMultivalued = false;
    versionParam.value = "published";

    SearchParam idParam = new SearchParam();
    idParam.fieldName = "contentId";
    idParam.isMultivalued = true;
    idParam.values = Arrays.asList("contentID-1", "contentID-2", "contentID-3");

    List<SearchParam> mustParams = Arrays.asList(versionParam, idParam);

    ObjectMapper mapper = new ObjectMapper();

    SimpleModule module = new SimpleModule();
    module.addSerializer(SearchParam.class, new SearchParamSerializer());
    module.addSerializer(DeleteQuery.class, new DeleteQuerySerializer());
    mapper.registerModule(module);

    DeleteQuery deleteQuery = new DeleteQuery();
    deleteQuery.mustParams = mustParams;

    String serialized = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(deleteQuery);
    System.out.println(serialized);
}

参考: jackson-custom-serialization

我在代码中进行了一些调整(例如在SearchParamSerializer.serialize()内部,重新安排jsonGen.writeStartObject()jsonGen.writeEndObject()相对于value.isMultivalued()条件),但仍未获得预期的结果

谷歌搜索和堆栈溢出后,我得到了很少的链接,但他们更多地谈论Gson库,和/或在python中。

任何帮助!

2 个答案:

答案 0 :(得分:0)

答案 1 :(得分:0)

我的解决方法现在继续。

修改了DeleteQueryDeleteQuerySerializer,如下所示:

class DeleteQuery {
    List<String> mustParams;
}

class DeleteQuerySerializer extends StdSerializer<DeleteQuery> {

    protected DeleteQuerySerializer(Class<DeleteQuery> t) {
        super(t);
    }

    public DeleteQuerySerializer() {
        this(null);
    }

    @Override
    public void serialize(DeleteQuery value, JsonGenerator jsonGen, SerializerProvider provider) throws IOException {
        jsonGen.writeStartObject();
        jsonGen.writeObjectFieldStart("query");
        jsonGen.writeObjectFieldStart("bool");
        String mustParam = String.join(",", value.mustParams);
        jsonGen.writeFieldName("must");
        jsonGen.writeRawValue("[" + mustParam + "]");
        jsonGen.writeEndObject();
    }
}

而且,这是dummyTest()

public void dummyTest() throws IOException {
    System.out.println();

    SearchParam versionParam = new SearchParam();
    versionParam.fieldName = "version";
    versionParam.isMultivalued = false;
    versionParam.value = "published";

    SearchParam idParam = new SearchParam();
    idParam.fieldName = "contentId";
    idParam.isMultivalued = true;
    idParam.values = Arrays.asList("contentId-123", "contentId-456", "xyz");

    List<SearchParam> mustParams = Arrays.asList(versionParam, idParam);

    ObjectMapper mapper = new ObjectMapper();

    SimpleModule module = new SimpleModule();
    module.addSerializer(SearchParam.class, new SearchParamSerializer());
    module.addSerializer(DeleteQuery.class, new DeleteQuerySerializer());
    mapper.registerModule(module);

    List<String> mustParamList = new ArrayList<>();
    for (SearchParam param : mustParams) {
        mustParamList.add(mapper.writeValueAsString(param));
    }

    DeleteQuery deleteQuery = new DeleteQuery();
    deleteQuery.mustParams = mustParamList;

    String serialized = mapper.writeValueAsString(deleteQuery);
    JsonNode jsonNode = mapper.readTree(serialized);
    String s = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonNode);
    System.out.println(s);
}

最后,得到了这个输出:

{
    "query": {
        "bool": {
            "must": [{
                "term": {
                    "version": {
                        "value": "published"
                    }
                }
            }, {
                "terms": {
                    "contentId": ["contentId-123", "contentId-456", "xyz"]
                }
            }]
        }
    }
}

:)

这不是一个合适的解决方案,但是我现在已经解锁了,可以继续下去。 :)