Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deserializing Polymorphic Types with @JsonUnwrapped using Jackson

What I Want to Do

I want to use Jackson to deserialize a polymorphic type, using the standard @JsonTypeInfo annotation as follows:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, 
              include = As.EXISTING_PROPERTY, 
              property = "identifier")
@JsonSubTypes({@Type(value = A.class, name = "A"),
               @Type(value = B.class, name = "B")})
abstract Class Base {}

Class A implements Base {
    public String identifier = "A";
}

Class B implements Base {
    public String identifier = "B";
}

Class Decorated {
    public String decoration = "DECORATION";

    @JsonUnwrapped
    public Base base;
}

/* 
    Serialized instance of Decorated WITHOUT @JsonUnwrapped:
    {
        "decoration" : "DECORATION",
        "base" : {
            "identifier" : "A"
        }
    }

    Serialized instance of Decorated WITH @JsonUnwrapped:
    {
        "decoration" : "DECORATION",
        "identifier" : "A"
    }
*/

Related post: Deserialize JSON with Jackson into Polymorphic Types - A Complete Example is giving me a compile error

This can normally be deserialized by Jackson as follows:

public Object deserialize(String body, Class clazz) {
    ObjectMapper objectMapper = new ObjectMapper();
    return objectMapper.readValue(body, clazz);
}

(And this would work if the @JsonUnwrapped annotation were removed)


The Problem

Polymorphic types do not play well with Jackson's @JsonUnwrapped annotation, as discussed in this Jira ticket from 2012:

http://markmail.org/message/pogcetxja6goycws#query:+page:1+mid:pogcetxja6goycws+state:results

Handle polymorphic types with @JsonUnwrapped

Agreed - while fixing things is obviously preferable, improving error messages would be useful if that can't be done.

Unwrapping is one of features where implementations gets complicated enough that any bugs cropping up (on deserialization esp) tend to be antibiotic-resistant...

Hardly encouraging.

Three years later:

http://markmail.org/message/cyeyc2ousjp72lh3

Handle polymorphic types with @JsonUnwrapped

Resolution: Won't Fix

Damn.

So, is there any way to coax Jackson into giving me this behaviour without modifying deserialize() or removing the @JsonUnwrapped annotation?

like image 245
Zaaier Avatar asked May 24 '16 21:05

Zaaier


1 Answers

My SinglePolyUnwrappedDeserializer from this Gist can handle a single polymorphic @JsonUnwrapped property. It's in Kotlin, but can easily be ported to Java if needed. Example:

@JsonTypeInfo(
    use = JsonTypeInfo.Id.NAME,
    include = JsonTypeInfo.As.PROPERTY,
    property = "type"
)
@JsonSubTypes(
    JsonSubTypes.Type(value = A::class, name = "a"),
    JsonSubTypes.Type(value = B::class, name = "b")
)
abstract class Base

data class A(val x: Int) : Base()

data class B(val y: Boolean) : Base()

@JsonDeserialize(using = SinglePolyUnwrappedDeserializer::class)
data class C(val a: String, @JsonUnwrapped val b: Base)

AFAIK, all combinations of other annotations are supported. The only limitation is that there is exactly one @JsonUnwrapped property.

If you also need a generic serializer for polymorphic @JsonUnwrapped, you can write it yourself very easily without any reflection or introspection: just merge the ObjectNode of the inner object onto the ObjectNode of the containing object.

like image 156
Anton3 Avatar answered Nov 09 '22 02:11

Anton3