How to create a custom deserializer in Jackson for a generic type?

Viewed 33542

Imagine the following scenario:

class <T> Foo<T> {
    ....
}

class Bar {
    Foo<Something> foo;
}

I want to write a custom Jackson deserializer for Foo. In order to do that (for example, in order to deserialize Bar class that has Foo<Something> property), I need to know the concrete type of Foo<T>, used in Bar, at deserialization time (e.g. I need to know that T is Something in that particluar case).

How does one write such a deserializer? It should be possible to do it, since Jackson does it with typed collections and maps.

Clarifications:

It seems there are 2 parts to solution of the problem:

1) Obtain declared type of property foo inside Bar and use that to deserialize Foo<Somehting>

2) Find out at deserialization time that we are deserializing property foo inside class Bar in order to successfully complete step 1)

How does one complete 1 and 2 ?

4 Answers

This is how you can access/resolve {targetClass} for a Custom Jackson Deserializer. Of course you need to implement ContextualDeserializer interface for this.

public class WPCustomEntityDeserializer extends JsonDeserializer<Object> 
              implements ContextualDeserializer {

    private Class<?> targetClass;

    @Override
    public Object deserialize(JsonParser jp, DeserializationContext ctxt)
            throws IOException, JsonProcessingException {

        ObjectCodec oc = jp.getCodec();
        JsonNode node = oc.readTree(jp);

        //Your code here to customize deserialization
        // You can access {target class} as targetClass (defined class field here)
        //This should build some {deserializedClasObject}

        return deserializedClasObject;

    }   

    @Override
    public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property){
        //Find here the targetClass to be deserialized  
        String targetClassName=ctxt.getContextualType().toCanonical();
        try {
            targetClass = Class.forName(targetClassName);
        } catch (ClassNotFoundException e) {            
            e.printStackTrace();
        }
        return this;
    }
}

For my use case, none of the above solutions worked, so I had to write a custom module. You can find my implementation on GitHub.

I wanted to write a deserializer that automatically removes blank Strings from Lists.

Related