Search code examples
javajsonjacksondeserialization

Deserializing polymorphic types with Jackson based on the presence of a unique property


If I have a class structure like so:

public abstract class Parent {
    private Long id;
    ...
}

public class SubClassA extends Parent {
    private String stringA;
    private Integer intA;
    ...
}

public class SubClassB extends Parent {
    private String stringB;
    private Integer intB;
    ...
}

Is there an alternative way to deserialize different then @JsonTypeInfo? Using this annotation on my parent class:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "objectType")

I would rather not have to force clients of my API to include "objectType": "SubClassA" to deserialize a Parent subclass.

Instead of using @JsonTypeInfo, does Jackson provide a way to annotate a subclass and distinguish it from other subclasses via a unique property? In my example above, this would be something like, "If a JSON object has "stringA": ... deserialize it as SubClassA, if it has "stringB": ... deserialize it as SubClassB".


Solution

  • This feels like something @JsonTypeInfo and @JsonSubTypes should be used for but I've picked through the docs and none of the properties that can be supplied quite seem to match what you're describing.

    You could write a custom deserializer that uses @JsonSubTypes' "name" and "value" properties in a non-standard way to accomplish what you want. The deserializer and @JsonSubTypes would be supplied on your base class and the deserializer would use the "name" values to check for the presence of a property and if it exists, then deserialize the JSON into the class supplied in the "value" property. Your classes would then look something like this:

    @JsonDeserialize(using = PropertyPresentDeserializer.class)
    @JsonSubTypes({
            @Type(name = "stringA", value = SubClassA.class),
            @Type(name = "stringB", value = SubClassB.class)
    })
    public abstract class Parent {
        private Long id;
        ...
    }
    
    public class SubClassA extends Parent {
        private String stringA;
        private Integer intA;
        ...
    }
    
    public class SubClassB extends Parent {
        private String stringB;
        private Integer intB;
        ...
    }