FreeBuilder icon indicating copy to clipboard operation
FreeBuilder copied to clipboard

Jackson deserializes generic parameter using default deserializer

Open mateuszlitwin opened this issue 8 years ago • 2 comments

Here is the test code:

package test;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import java.io.IOException;
import org.inferred.freebuilder.FreeBuilder;

@FreeBuilder
@JsonDeserialize(builder = GenericType.Builder.class)
interface GenericType<T> {
    T getValue();

    //@JsonCreator
    //static <T> GenericType of(@JsonProperty("value") T value) {
    //    return new GenericType.Builder<>().setValue(value).build();
    //}

    class Builder<T> extends GenericType_Builder<T> {}
}

public class Test {
    public static void main(String[] args) throws IOException {
        String json = "{\"value\": \"123\"}";
        ObjectMapper objectMapper = new ObjectMapper();
        JavaType javaType = objectMapper.getTypeFactory().constructParametricType(
                GenericType.class,
                Long.class);
        GenericType<Long> object = objectMapper.readValue(json, javaType);
        System.out.println(object.getValue().getClass());
    }
}

If you run it, it should result in Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Long.

However changing deserialization from @JsonDeserialize(builder = GenericType.Builder.class) to static @JsonCreator seems to solve the problem, but ideally we don't want to write this manually.

It is worth noting that using String json = "{\"value\": 123}"; result in java.lang.Integer being deserialized instead of java.lang.Long. So it looks like Jackson is picking up some default deserialization method (String for JSON String, Integer for JSON Number) instead of trying to deserialize into custom type. It is especially annoying if you try to use StringWrapper-like classes.

Tested with jackson 2.4.4 and 2.6.5.

mateuszlitwin avatar Sep 11 '16 20:09 mateuszlitwin

It seems to be caused by https://github.com/FasterXML/jackson-databind/issues/921

I suggest maybe generating @JsonCreator code to fix this issue? It will also get rid of @JsonDeserialize.

mateuszlitwin avatar Sep 11 '16 20:09 mateuszlitwin

Thanks for the investigative work, @divath! I'll leave this as an open "upstream bug" for reference, but I don't think we should be working around open Jackson bugs. (That said, if you release a FreeBuilder fix and commit to maintaining it, that's a different matter 😉 )

alicederyn avatar Sep 13 '16 13:09 alicederyn