On Jackson: Serializing Lists, Maps with properties
1. Problem
One of questions occasionally brought up is why Jackson ignores any properties that a java.util.List or java.util.Map may have. For example, for:
public class StringList extends ArrayList<String> {
public int id;
}
the serialized version will just be a JSON array, without property "id". This is also true for Java Maps: only contents are serialized, not properties. This is because serializers (and deserializers) have special handling; and in case of Lists, there isn't even any place to add properties in.
2. Solution
But is there any way to add support for additional properties, without resorting to custom serializers and deserializers?
Yes! With Jackson 2.1 and above there is a new annotation, @JsonFormat, and specifically its "shape" property.
Like so:
@JsonFormat(shape=JsonFormat.Shape.OBJECT)
public class StringListexten ds ArrayList<String> {
public int id;
public Iterator<String> getValues() { return iterator(); }
public void setValues(Collection<String> v) { addAll(v); }
}
What does this do? It will basically instruct Jackson to forget about special handling for Collections and Maps, and instead consider them POJOs. This means that introspection is used to find logical properties to (de)serialize.
One caveat: since there is no special handling for contents, you HAVE to add getter/setter to actually include contents.
3. Output
For type like above, you would get something like:
{ "id":123, "values":["abc","xyz"]}
Similarly for Maps, you would get properties at one JSON Object level, and values (if included) as a JSON Object-valued property:
{ "id" : 345,
"value" : {
"key1":"value1",
"key2":"value2" }
}
Or, for extra credit, you can even try using "any setter" and "any getter", to create a Map with flat set of values -- this works, since Map is just like any POJO from Jackson's point of view now.