Jackson polymorphic deserialization with nested type info property

旧街凉风 提交于 2019-12-21 12:01:21

问题


I'm constrained by the given JSON structure:

{
  "metadata": {
    "eventName": "FooEvent",
    "field1": "bla"
  },
  "event": { ... }
}

How can I deserialize it using polymorphic deserialization and nested type info property? I'm using metadata.eventName nested property in @JsonTypeInfo like this:

@JsonTypeInfo(
    use = Id.NAME,
    include = As.EXISTING_PROPERTY,
    visible = true,
    property = "metadata.eventName"
)
@JsonSubTypes({
    @Type(name="fooEvent", value = FooEvent.class)
    @Type(name="barEvent", value = BarEvent.class)
})
public class EventPayload<T> {
     private Metadata metadata;
     private T event;
}

Given that config Jackson complains the property cannot be found:

com.fasterxml.jackson.databind.JsonMappingException: Unexpected token (END_OBJECT), expected FIELD_NAME: missing property 'metadata.eventName' that is to contain type id  (for class EventPayload)
 at [Source: {
  "metadata": {
     "eventName": "FooEvent",
     "field1": "bla"
  },
  "content": { ... }
}; line: 16, column: 1]

回答1:


You are facing 2 issues here:

  1. As you have seen Jackson cannot easily and just by annotations use a property in a nested JSON object to deduce the type to deserialize to.
  2. @JsonTypeInfo and @JsonSubTypes are meant for inheritance e.g class FooEventPayload extends EventPayload. In your case EventPayload<T> is a generic class and Jackson needs to be told what T is with a TypeReference Look here for instance

Assuming you want a generic class I'd suggest serialize into a tree first, peek into the tree to get the property that specifies the type and then convert the tree to an object of this type. You can skip @JsonTypeInfo and @JsonSubTypes. E.g.

// user object mapper to parse JSON into a tree (node is the root) 
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readTree(jsonString);

// use get as many times as needed by depth
// to get the value that defines the type to deserialise to
String type = node.get("metadata").get("eventName").textValue();

// convert JsonNode variable to the required type
if (type.equals("fooEvent")) {
    EventPayload<FooEvent> event = 
        mapper.convertValue(node, new TypeReference<EventPayload<FooEvent>>(){});
} else if (type.equals("barEvent")) {
    EventPayload<BarEvent> event =
        mapper.convertValue(node, new TypeReference<EventPayload<BarEvent>>(){});
}


来源:https://stackoverflow.com/questions/48381795/jackson-polymorphic-deserialization-with-nested-type-info-property

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!