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

Custom deserializer with parent object update #744

Closed
migel opened this issue Mar 30, 2015 · 4 comments
Closed

Custom deserializer with parent object update #744

migel opened this issue Mar 30, 2015 · 4 comments
Milestone

Comments

@migel
Copy link

migel commented Mar 30, 2015

Hi, I have custom deserializer for DataA. An instance of DataA is contained in DataB, when updating an existing instance of DataB (as opposed to creating a new one) I get an exception when deserializing via a JsonNode object (deserializing via a String object works).

import java.io.IOException;

import org.junit.Assert;
import org.junit.Test;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;

public class TestDeserTest {
    static class DataA {
        public int i = 1;
        public int j = 2;

    }

    static class DataB {
        public DataA da = new DataA();
        public int k = 3;
    }

    static class DataADeserializer extends StdDeserializer<DataA> {
        private static final long serialVersionUID = 1L;

        DataADeserializer() {
            super(DataA.class);
        }

        public DataA deserialize(JsonParser jp, DeserializationContext ctxt)
                throws JsonProcessingException, IOException {
            assert (jp.getCurrentToken() == JsonToken.START_OBJECT);
            JsonNode node = jp.getCodec().readTree(jp);

            DataA da = new DataA();
            da.i = 5;
            return da;
        }
    }

    @Test
    public void test() throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        SimpleModule module = new SimpleModule();
        module.addDeserializer(DataA.class, new DataADeserializer());
        mapper.registerModule(module);

        DataB db = new DataB();
        db.da.i = 11;
        db.k = 13;
        String jsonBString = mapper.writeValueAsString(db);
        JsonNode jsonBNode = mapper.valueToTree(db);

        // create parent
        DataB dbNewViaString = mapper.readValue(jsonBString, DataB.class);
        Assert.assertEquals(5, dbNewViaString.da.i);
        Assert.assertEquals(13, dbNewViaString.k);

        DataB dbNewViaNode = mapper.treeToValue(jsonBNode, DataB.class);
        Assert.assertEquals(5, dbNewViaNode.da.i);
        Assert.assertEquals(13, dbNewViaNode.k);

        // update parent
        DataB dbUpdViaString = new DataB();
        DataB dbUpdViaNode = new DataB();

        Assert.assertEquals(1, dbUpdViaString.da.i);
        Assert.assertEquals(3, dbUpdViaString.k);
        mapper.readerForUpdating(dbUpdViaString).readValue(jsonBString);
        Assert.assertEquals(5, dbUpdViaString.da.i);
        Assert.assertEquals(13, dbUpdViaString.k);

        Assert.assertEquals(1, dbUpdViaNode.da.i);
        Assert.assertEquals(3, dbUpdViaNode.k);
        // FAILS HERE:
        mapper.readerForUpdating(dbUpdViaNode).readValue(jsonBNode);
        Assert.assertEquals(5, dbUpdViaNode.da.i);
        Assert.assertEquals(13, dbUpdViaNode.k);
    }
}

The trace:

com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "i" (class myorg.TestDeserTest$DataB), not marked as ignorable (2 known properties: "da", "k"])
 at [Source: N/A; line: -1, column: -1] (through reference chain: myorg.DataB["da"]->myorg.DataB["i"])
    at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:51)
    at com.fasterxml.jackson.databind.DeserializationContext.reportUnknownProperty(DeserializationContext.java:817)
    at com.fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:954)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperty(BeanDeserializerBase.java:1324)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownVanilla(BeanDeserializerBase.java:1302)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:249)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:136)
    at com.fasterxml.jackson.databind.ObjectReader._bindAsTree(ObjectReader.java:1478)
    at com.fasterxml.jackson.databind.ObjectReader.readTree(ObjectReader.java:1020)
    at myorg.TestDeserTest$DataADeserializer.deserialize(TestDeserTest.java:39)
    at myorg.TestDeserTest$DataADeserializer.deserialize(TestDeserTest.java:1)
    at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:523)
    at com.fasterxml.jackson.databind.deser.impl.FieldProperty.deserializeAndSet(FieldProperty.java:101)
    at com.fasterxml.jackson.databind.deser.impl.BeanPropertyMap.findDeserializeAndSet(BeanPropertyMap.java:285)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:220)
    at com.fasterxml.jackson.databind.ObjectReader._bindAndClose(ObjectReader.java:1443)
    at com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:1154)
    at myorg.TestDeserTest.test(TestDeserTest.java:81)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    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.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
@migel migel changed the title Custom deserializer with object update Custom deserializer with parent object update Mar 30, 2015
@cowtowncoder
Copy link
Member

Interesting. I can reproduce it with given test case.

One thing I notice is that replacing jp.getCodec().readTree(jp) (or simpler equivalent of jp.readValueAsTree()) give the exception; but simple jp.skipChildren() does not.
So something in reading-as-tree is not working as expected...

@cowtowncoder
Copy link
Member

Whoa. Internally it looks like JsonNode deserializer is resolved to be deserializer for DataA... wires getting crossed badly somewhere.

@cowtowncoder
Copy link
Member

Actually, not problem with caching, but rather with _rootDeserializer that ObjectReader caches locally. Need to see how this can be by-passed.

@cowtowncoder cowtowncoder added this to the 2.5.3 milestone Apr 2, 2015
cowtowncoder added a commit that referenced this issue Apr 2, 2015
cowtowncoder added a commit that referenced this issue Apr 2, 2015
@cowtowncoder
Copy link
Member

Fixed in 2.5.3, although I did also backport it in 2.4.6 just in case.

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