crm86
crm86

Reputation: 1394

Jackson dynamic Pojo <T> Deseralization

Having a dynamic POJO like the next one:

@JsonInclude(JsonInclude.Include.NON_NULL)
public class MyDynamicWrapper <T> {

    @JsonProperty("header")
    private CommonHeader header;

    @JsonProperty("payload")
    private T payload;

    public MyDynamicWrapper(CommonHeader header, T payload) {
        super();
        this.header = header;
        this.payload = payload;
    }

    public CommonHeader getHeader() {
        return header;
    }

    public void setHeader(CommonHeader header) {
        this.header = header;
    }

    public T getPayload() {
        return payload;
    }

    public void setPayload(T payload) {
        this.payload = payload;
    }
}

Where T payload could be one of the following:

@JsonInclude(JsonInclude.Include.NON_NULL)
public class MyPayloadOne {

    @JsonProperty("status")
    private int status; 

    @JsonProperty("action")
    private String action;  

    ...
}

@JsonInclude(JsonInclude.Include.NON_NULL)
public class MyPayloadTwo {

    @JsonProperty("properties")
    private List<String> properties = new ArrayList<>();    

    ...
}

What is the best way to deserialize this dynamic information with Jackson? Is it mandatory to implement a deserializer? My current configuration is not dynamic and I am using:

MyDynamicWrapper pojo = jacksonMapper.readValue(jsonMessage, MyDynamicWrapper.class);

I think this is so obvious but I do not know how to indicate the dynamic reference to Jackson.

Update

In addition to the accepted answer, I have checked that also is possible to define the jackson mapper like this:

MyDynamicWrapper<?> pojo = jacksonMapper.readValue(jsonMessage, MyDynamicWrapper.class);

This will transform the POJO to both payloads.

Upvotes: 1

Views: 922

Answers (4)

Sanjeev Sachdev
Sanjeev Sachdev

Reputation: 1321

If you know the type parameter at compile time then you may use TypeReference to deserialize the JSON as described in the accepted answer.
In case type parameter is not known at compile time, even then JSON can be deserialized. To achieve this you would need to put certain Jackson annotations on all the classes that can be passed as type parameter to the generic MyDynamicWrapper<T>.

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT)
@JsonTypeName("MyPayloadOne")
public class MyPayloadOne {

}

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT)
@JsonTypeName("MyPayloadTwo ")
public class MyPayloadTwo {

}

Now when you deserialize an instance of MyDynamicWrapper created using either MyPayloadOne or MyPayloadTwo as parameter, Jackson will put type parameter info into JSON. This JSON can then be deserialized into generic class MyDynamicWrapper.class just as you would deserialize any other class, i.e., without having to specify the type parameter (MyPayloadOne or MyPayloadTwo).

MyDynamicWrapper<?> pojo = jacksonMapper.readValue(jsonString, MyDynamicWrapper.class);

Please refer Jackson documentation on Polymorphic Deserialization and Annotations.

Upvotes: 0

Manos Nikolaidis
Manos Nikolaidis

Reputation: 22234

You can (and should) pass a TypeReference to readValue to specify the type of generic class instance you want to deserialize. E.g. when wrapping MyPayloadOne:

TypeReference ref = new TypeReference<MyDynamicWrapper<MyPayloadOne>>(){};
MyDynamicWrapper<MyPayloadOne> pojo = jacksonMapper.readValue(jsonMessage, ref);

Upvotes: 1

Joshua Hendrickson
Joshua Hendrickson

Reputation: 1

Try using @JsonCreator and @JsonProperty as specified in this question. Is Jackson really unable to deserialize json into a generic type?

Jackson needs a little more help to figure out what type to deserialize, and that's what those annotations help to do.

Upvotes: 0

ben
ben

Reputation: 1

You will need to write a custom serializer by implementing this class. Or Deserializer

Upvotes: 0

Related Questions