簡體   English   中英

使用Jackson JSON Generator,如何將多個對象寫入一個字段?

[英]Using Jackson JSON Generator, how can I write multiple objects to one field?

假設我有以下三個類(為了簡潔省略了getter和setter):

@JsonAutoDetect
public class InfoCollection{
    private InfoType1 info1;
    private InfoType2 info2;
}

@JsonAutoDetect
public class InfoType1{
    private String fieldA;
}

@JsonAutoDetect
public class InfoType2{
    private String fieldB;
}

我正在嘗試編寫一個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

我錯過了一些小事情,還是我完全錯誤地采取了這種做法?

注意:到目前為止,提出的一些解決方案涉及編寫InfoType1InfoType2每個字段。 我正在尋找一個不需要這個的解決方案,因為我想在具有許多領域的大型類上使用該解決方案。

您應該調用writeObjectFieldStart("allInfo")而不是調用writeFieldName("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_ROOT_VALUE功能才能使其正常工作。請參閱序列化功能

將來,當您有堆棧跟蹤時,請告訴我們問題出現在哪一行。

也就是說,修復可能是:

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 );

collectFields應檢查所有字段並將所有內容添加到列表中,該列表可以是基元,也可以是field.getType().getName().startsWith("java.lang")或您需要的任何其他規則。

如果該字段是引用,則遞歸調用collectFields()

當你有列表時,只需在循環中調用jsonGenerator來編寫結果。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM