Alexander Müller
Alexander Müller

Reputation: 547

Jackson: JsonTypeInfo does not add property

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?

Upvotes: 3

Views: 5876

Answers (3)

Alexander Müller
Alexander Müller

Reputation: 547

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

Upvotes: 8

AbuNassar
AbuNassar

Reputation: 1235

You may need to specify EXTERNAL_PROPERTY here, as the class in question has no "type" property.

Upvotes: 1

manuna
manuna

Reputation: 871

Perhaps you need a field "type" in your Group class? Like this: private String type; with getter and setter, of course

Upvotes: 0

Related Questions