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

CFL_Jeff picture CFL_Jeff · Feb 12, 2013 · Viewed 39.6k times · Source

Suppose I have the following three classes (getters and setters left out for brevity):

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

@JsonAutoDetect
public class InfoType1{
    private String fieldA;
}

@JsonAutoDetect
public class InfoType2{
    private String fieldB;
}

I"m trying to write a JsonSerializer.serialize() function that serializes an InfoCollection object in this format:

{
    "allInfo":{
        "fieldA":"foo",
        "fieldB":"bar"
    }
}

This is what I have now:

jsonGenerator.writeStartObject();
jsonGenerator.writeFieldName("allInfo");
jsonGenerator.writeObject(myInfoCollection.getInfo1());
jsonGenerator.writeObject(myInfoCollection.getInfo2());
jsonGenerator.writeEndObject();

which is causing the following exception:

 org.codehaus.jackson.JsonGenerationException: Can not start an object, expecting field name

Am I missing something small or am I totally going about this the wrong way?

NOTE: A couple of the proposed solutions so far involve writing each individual field of InfoType1 and InfoType2. I am looking for a solution that does not require this because I'd like to use the solution on huge classes with many fields.

Answer

Alex Vayda picture Alex Vayda · Feb 12, 2013

Instead of calling writeFieldName("allInfo") you should call writeObjectFieldStart("allInfo") because "allInfo" is another JSON object. So your custom serializer should look the following way:

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

Or you may try annotation based approach:

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

    /* getters, setters */
}

(You need to enable SerializationConfig.Feature.WRAP_ROOT_VALUE feature in order for this to work. See Serialization features)