Given the following POJOs ..
public class City {
private String title;
private List<Person> people;
}
...
public class Person {
private String name;
private int age;
}
I would like to let Jackson serialize instances of the classes to the following example JSON:
{
"title" : "New York",
"personName_1" : "Jane Doe",
"personAge_1" : 42,
"personName_2" : "John Doe",
"personAge_2" : 23
}
The JSON format is defined by an external API which I cannot change.
I already found that I can annotate the list field with a custom serializer such as:
@JsonSerialize(using = PeopleSerializer.class)
private List<Person> people;
... and here is a basic implementation I tried:
public class PeopleSerializer extends JsonSerializer<List<Person>> {
private static final int START_INDEX = 1;
@Override
public void serialize(List<Person> people,
JsonGenerator generator,
SerializerProvider provider) throws IOException {
for (int i = 0; i < people.size(); ++i) {
Person person = people.get(i);
int index = i + START_INDEX;
serialize(person, index, generator);
}
}
private void serialize(Person person, int index, JsonGenerator generator) throws IOException {
generator.writeStringField(getIndexedFieldName("personName", index),
person.getName());
generator.writeNumberField(getIndexedFieldName("personAge", index),
person.getAge());
}
private String getIndexedFieldName(String fieldName, int index) {
return fieldName + "_" + index;
}
}
However, this fails with an:
JsonGenerationException: Can not write a field name, expecting a value
I also looked into using Jackson's Converter interface but that's not suitable for unwrapping the nested list objects.
I am also aware of @JsonUnwrapped
but it is not designed to be used with lists.
Related posts
- Serialize List content in a flat structure in jackson json (Java)
- Jackson: How to add custom property to the JSON without modifying the POJO
- How to serialize only the ID of a child with Jackson
You can use the
BeanSerializerModifier
to directly modify how a property name and value are written. Using this you could detect if a custom annotation is present, in this case I made one called@FlattenCollection
. When the annotation is present the array or collection is not written using the normal method but instead written by a custom property writer (FlattenCollectionPropertyWriter
).This annotation will likely break on 2d arrays or other edge cases, I havent tested those but you could probably code for them without to much trouble, at least throw a meaningful error.
Heres the full working code. Notable points are
Output:
Code:
Based on this link I suspect the field-level annotation only delegates writing the value not entire properties.
A (rather kludgey) workaround might be to have a custom serializer for the entire City class:
...and then