Java 使用Jackson JSON生成器,如何将多个对象写入一个字段?

Java 使用Jackson JSON生成器,如何将多个对象写入一个字段?,java,json,jackson,jsonserializer,Java,Json,Jackson,Jsonserializer,假设我有以下三个类(为了简洁起见省略了getter和setter): 我正在尝试编写一个JsonSerializer.serialize()函数,以以下格式序列化InfoCollection对象: { "allInfo":{ "fieldA":"foo", "fieldB":"bar" } } 这就是我现在拥有的: jsonGenerator.writeStartObject(); jsonGenerator.writeFieldName("al

假设我有以下三个类(为了简洁起见省略了getter和setter):

我正在尝试编写一个
JsonSerializer.serialize()
函数,以以下格式序列化
InfoCollection
对象:

{
    "allInfo":{
        "fieldA":"foo",
        "fieldB":"bar"
    }
}
这就是我现在拥有的:

jsonGenerator.writeStartObject();
jsonGenerator.writeFieldName("allInfo");
jsonGenerator.writeObject(myInfoCollection.getInfo1());
jsonGenerator.writeObject(myInfoCollection.getInfo2());
jsonGenerator.writeEndObject();
这导致了以下异常:

 org.codehaus.jackson.JsonGenerationException: Can not start an object, expecting field name
我是错过了一些小的东西,还是我完全走错了方向


注意:目前提出的两种解决方案涉及编写
InfoType1
InfoType2
的每个字段。我正在寻找一种不需要这样做的解决方案,因为我希望在具有许多字段的大型类上使用该解决方案。

将来,当您有堆栈跟踪时,请告诉我们问题出现在哪一行

也就是说,解决办法可能是:

jsonGenerator.writeStartObject();
jsonGenerator.writeFieldName("allInfo");

jsonGenerator.writeStartObject(); // start nested object
jsonGenerator.writeFieldName("fieldA"); // start field
jsonGenerator.writeObject(myInfoCollection.getInfo1().fieldA);

jsonGenerator.writeFieldName("fieldB"); // start fieldB
jsonGenerator.writeObject(myInfoCollection.getInfo2().fieldB);

jsonGenerator.writeEndObject(); // end nested object

jsonGenerator.writeEndObject();
使用包装器对象的解决方案:

@JsonAutoDetect
public class Wrapper {
    private transient InfoCollection data; // transient makes Jackson ignore this

    public String getFieldA() { return data.info1.fieldA; }
    public String getFieldB() { return data.info1.fieldB; }
}
这让杰克逊只看到你想要什么和你想要什么

或者,使用反射递归收集所有字段及其名称:

List<Pair<String, Object>> data = collectFields( myInfoCollection );
List data=collectFields(myInfoCollection);
collectFields
应该检查所有字段,并将所有内容添加到列表中,这些内容可以是原语,也可以是where
field.getType().getName().startsWith(“java.lang”)
或任何其他需要的规则

如果字段是引用,则递归调用
collectFields()


有了列表后,只需在循环中调用
jsonGenerator
即可写入结果。

而不是调用
writeFieldName(“allInfo”)
您应该调用
writeObjectFieldStart(“allInfo”)
,因为“allInfo”是另一个JSON对象。因此您的自定义序列化程序应该如下所示:

public void serialize(InfoCollection infoCollection, JsonGenerator jgen, SerializerProvider provider) throws IOException{
    jgen.writeStartObject();
    jgen.writeObjectFieldStart("allInfo");
    jgen.writeObjectField("fieldA", infoCollection.getInfo1().getFieldA());
    jgen.writeObjectField("fieldB", infoCollection.getInfo2().getFieldB());
    jgen.writeEndObject();
    jgen.writeEndObject();
}
或者,您可以尝试基于注释的方法:

@JsonRootName("allInfo")
public class InfoCollection {
    @JsonUnwrapped
    private InfoType1 info1;
    @JsonUnwrapped
    private InfoType2 info2;

    /* getters, setters */
}

(您需要启用
SerializationConfig.Feature.WRAP\u ROOT\u VALUE
功能才能正常工作。请参阅)

此方法可能会起作用,但它让我编写每个单独的字段。我正在尝试提出一个解决方案,可以应用于具有更多字段的较大类。使用反射和注释来定位要编写的字段,并从允许重用代码的两个帮助器方法/类构建生成器。Alter本机,创建一个包装类,为您提供一个更接近Jackson应该创建的输出的API。但这仍然归结为将来自不同POJO的字段组合到一个JSON对象的问题。即使使用注释和/或包装类,我也想不出一种方法。也许您可以更改demonstr的答案是否使用此方法?此方法可能会起作用,但它让我编写每个字段。我正在尝试提出一个解决方案,可以应用于具有更多字段的更大类。您也可以使用注释来执行此操作,但它不如自定义序列化器灵活。我已使用基于注释的示例更新了答案。
@JsonRootName("allInfo")
public class InfoCollection {
    @JsonUnwrapped
    private InfoType1 info1;
    @JsonUnwrapped
    private InfoType2 info2;

    /* getters, setters */
}