FasterXML/jackson-module-afterburner

Specific ordering of type information for polymorphic deserialization

steveme opened this issue · 3 comments

Hi,

Encountering the following problem with jackson-module-afterburner:2.6.1where the class attribute has to be after the polymorphic value in deserialization.

Succeeds:

{"payload":{"something":"test"},"class":"Payload"}

Throws exception below:

{"class":"Payload","payload":{"something":"test"}}
com.fasterxml.jackson.databind.JsonMappingException: Problem deserializing property 'payload' (expected type: [simple type, class java.lang.Object]; actual type: Payload), problem: Can not set java.lang.Object field Envelope.payload to com.fasterxml.jackson.databind.deser.impl.PropertyValueBuffer
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.module.afterburner.AfterburnerModule;
import org.junit.Test;

import java.io.IOException;


class Envelope {
    @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.EXTERNAL_PROPERTY, property = "class")
    private Object payload;


    public Envelope(@JsonProperty("payload") Object payload) {
        this.payload = payload;
    }

    @JsonProperty
    public Object getPayload() {
        return payload;
    }
}

class Payload {
    private String something;

    public Payload(@JsonProperty("something") String something) {
        this.something = something;
    }

    @JsonProperty
    public Object getSomething() {
        return something;
    }
}


public class AfterBurnerTest {
    @Test
    public void testAfterburner() throws IOException {
        String successCase = "{\"payload\":{\"something\":\"test\"},\"class\":\"Payload\"}";
        String failCase = "{\"class\":\"Payload\",\"payload\":{\"something\":\"test\"}}";

        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(new AfterburnerModule());

        Envelope envelope1 = mapper.readValue(successCase, Envelope.class);
        Envelope envelope2 = mapper.readValue(failCase, Envelope.class);

    }
}

The exception:

com.fasterxml.jackson.databind.JsonMappingException: Problem deserializing property 'payload' (expected type: [simple type, class java.lang.Object]; actual type: Payload), problem: Can not set java.lang.Object field Envelope.payload to com.fasterxml.jackson.databind.deser.impl.PropertyValueBuffer

    at com.fasterxml.jackson.databind.deser.SettableBeanProperty._throwAsIOE(SettableBeanProperty.java:546)
    at com.fasterxml.jackson.databind.deser.impl.FieldProperty.set(FieldProperty.java:128)
    at com.fasterxml.jackson.databind.deser.CreatorProperty.set(CreatorProperty.java:201)
    at com.fasterxml.jackson.databind.deser.CreatorProperty.deserializeAndSet(CreatorProperty.java:180)
    at com.fasterxml.jackson.databind.deser.impl.ExternalTypeHandler._deserializeAndSet(ExternalTypeHandler.java:253)
    at com.fasterxml.jackson.databind.deser.impl.ExternalTypeHandler.handlePropertyValue(ExternalTypeHandler.java:119)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeUsingPropertyBasedWithExternalTypeId(BeanDeserializer.java:792)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeWithExternalTypeId(BeanDeserializer.java:716)
    at com.fasterxml.jackson.module.afterburner.deser.SuperSonicBeanDeserializer.deserializeFromObject(SuperSonicBeanDeserializer.java:234)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:131)
    at com.fasterxml.jackson.module.afterburner.deser.SuperSonicBeanDeserializer.deserialize(SuperSonicBeanDeserializer.java:117)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3702)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2714)
    at AfterBurnerTest.testAfterburner(AfterBurnerTest.java:49)
    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:497)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:117)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)
    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:497)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
Caused by: java.lang.IllegalArgumentException: Can not set java.lang.Object field Envelope.payload to com.fasterxml.jackson.databind.deser.impl.PropertyValueBuffer
    at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
    at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
    at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:58)
    at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:75)
    at java.lang.reflect.Field.set(Field.java:764)
    at com.fasterxml.jackson.databind.deser.impl.FieldProperty.set(FieldProperty.java:126)
    ... 38 more

Sounds like a bug. Thank you for reporting this.

Seems to also affect 2.5.

I suspect the real culprit is the one from databind; with that fix, Afterburner test passes.