Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Builder deserailizer: in-compatible type exception when return type is super type #761

Closed
agavrilov76 opened this issue Apr 19, 2015 · 0 comments
Milestone

Comments

@agavrilov76
Copy link
Contributor

Based on the following stack overflow question: http://stackoverflow.com/questions/29724859/jackson-deserialization-with-builder-pattern-build-method-has-bad-return-type

The builder deserailizer throws the "Build method has bad return type, not compatible with POJO type” exception if the build method return type is a super type of the POJO type. Here is a complete example:

public class JacksonBuilder {
    public interface FooInterface {
    }

    public static class Foo implements FooInterface {
        public static final class Builder {
            @JsonProperty
            public Builder valueA(String value) { return this; }
            @JsonProperty
            public Builder valueB(String value) { return this; }
            public FooInterface build() { return new Foo() {}; }
        }
    }

    @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
    @JsonSubTypes({
            @JsonSubTypes.Type(value = Foo.class, name = "foo")})
    public static abstract class FooInterfaceMixin {}

    @JsonTypeName("foo")
    @JsonDeserialize(builder=Foo.Builder.class)
    public static abstract class FooMixin {}

    public static void main(String[] args) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        mapper.addMixIn(FooInterface.class, FooInterfaceMixin.class);
        mapper.addMixIn(Foo.class, FooMixin.class);

        final String jsonString = "{\"type\":\"foo\", \"valueA\":\"a\", \"valueB\":\"b\"}";
        FooInterface foo = mapper.readValue(jsonString, FooInterface.class);
    }
}

Output:

Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: Build method 'stackoverflow.JacksonBuilder$Foo$Builder#build(0 params) has bad return type (stackoverflow.JacksonBuilder$FooInterface), not compatible with POJO type (stackoverflow.JacksonBuilder$Foo)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:270)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:245)
    at com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:143)
    at com.fasterxml.jackson.databind.DeserializationContext.findContextualValueDeserializer(DeserializationContext.java:406)
    at com.fasterxml.jackson.databind.jsontype.impl.TypeDeserializerBase._findDeserializer(TypeDeserializerBase.java:176)
    at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer._deserializeTypedForId(AsPropertyTypeDeserializer.java:110)
    at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer.deserializeTypedFromObject(AsPropertyTypeDeserializer.java:95)
    at com.fasterxml.jackson.databind.deser.AbstractDeserializer.deserializeWithType(AbstractDeserializer.java:131)
    at com.fasterxml.jackson.databind.deser.impl.TypeWrappedDeserializer.deserialize(TypeWrappedDeserializer.java:42)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3562)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2578)
    at stackoverflow.JacksonBuilder.main(JacksonBuilder.java:48)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
Caused by: java.lang.IllegalArgumentException: Build method 'stackoverflow.JacksonBuilder$Foo$Builder#build(0 params) has bad return type (stackoverflow.JacksonBuilder$FooInterface), not compatible with POJO type (stackoverflow.JacksonBuilder$Foo)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBuilder.buildBuilderBased(BeanDeserializerBuilder.java:378)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.buildBuilderBasedDeserializer(BeanDeserializerFactory.java:297)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.createBuilderBasedDeserializer(BeanDeserializerFactory.java:155)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer(DeserializerCache.java:351)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:265)
    ... 16 more

It seems that the condition at

if (!valueType.getRawClass().isAssignableFrom(rawBuildType)) {
should be reversed to:

!rawBuildType.isAssignableFrom(valueType.getRawClass())

to allow rawBuildType be a super type of the valueType.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants