Jackson: JsonTypeInfo does not add property
jackson, jpa, json, polymorphism, spring-mvc
Solution
The problem is the controller action:
@RequestMapping(...)
@ResponseBody
public Map<String, Object> getGroups() {
Map<String, Object> response = new HashMap<String, Object>();
List<Group> groups = magicallyRetrieveGroupsFromNarnia();
response.put("groups", groups);
response.put("status", Status.OK);
return response;
}
It returns a map of String-Object tuples. The MappingJackson2HttpMessageConverter throws this map into the ObjectMapper. The ObjectMapper doesn't care about @JsonTypeInfo for the supplied map contents, because it doesn't know about it. All it sees are type-erased List instances in uncomfortable Object-suits.
There are multiple ways to resolve this problem:
- Use Map>.
- Disadvantage: You cannot mix types (ints, strings, complex objects, lists, ...).
- Advantage: Pretty easy.
- Create an explicit GroupList.
- Disadvantage: Clutter.
- Advantage: Works with Map.
- Create a complex object with explicit fields.
- Disadvantage: Clutter.
- Advantage: Works with Map.
- Use a typed writer in a custom MappingJackson2HttpMessageConverter extension.
- Disadvantage: Rather complex.
- Advantage: Flexible as hell.
This JIRA issue helped me understand the problem: https://github.com/FasterXML/jackson-databind/issues/364
Problem
I am trying to use Jackson to serialize entities with polymorphism. The serialized JSON string should include an additional "type" property with "groupA" or "groupB" as value, but it doesn't. My entities look like this: ``` @Entity @Table(name = "\"group\"") @Inheritance(strategy = InheritanceType.JOINED) @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type") @JsonSubTypes({ @JsonSubTypes.Type(value = GroupA.class, name = "groupA"), @JsonSubTypes.Type(value = GroupB.class, name = "groupB") }) @JsonSerialize(include = JsonSerialize.Inclusion.ALWAYS) public class Group implements Serializable { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Integer id; // ... } @Entity @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type") @JsonSerialize(include = JsonSerialize.Inclusion.ALWAYS) public class GroupA extends Group { //... } @Entity @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type") @JsonSerialize(include = JsonSerialize.Inclusion.ALWAYS) public class GroupB extends Group { // ... } ``` Do you know why the serializer does not add the type property?