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

Problem deserializing polymorphic types with @JsonCreator #113

Closed
ihr opened this issue Nov 19, 2012 · 20 comments
Closed

Problem deserializing polymorphic types with @JsonCreator #113

ihr opened this issue Nov 19, 2012 · 20 comments
Milestone

Comments

@ihr
Copy link

ihr commented Nov 19, 2012

I get a NPE when trying to de-serialize a hierarchy of objects. Here is the stack trace:

java.lang.NullPointerException
    at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.addBeanProps(BeanDeserializerFactory.java:542)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.buildBeanDeserializer(BeanDeserializerFactory.java:267)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.createBeanDeserializer(BeanDeserializerFactory.java:171)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer(DeserializerCache.java:388)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:264)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:244)
    at com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:143)
    at com.fasterxml.jackson.databind.DeserializationContext.findContextualValueDeserializer(DeserializationContext.java:325)
    at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.createContextual(CollectionDeserializer.java:147)
    at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.createContextual(CollectionDeserializer.java:23)
    at com.fasterxml.jackson.databind.DeserializationContext.findContextualValueDeserializer(DeserializationContext.java:329)
    at com.fasterxml.jackson.databind.deser.impl.PropertyBasedCreator.construct(PropertyBasedCreator.java:96)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.resolve(BeanDeserializerBase.java:406)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:295)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:244)
    at com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:143)
    at com.fasterxml.jackson.databind.DeserializationContext.findContextualValueDeserializer(DeserializationContext.java:325)
    at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.createContextual(CollectionDeserializer.java:147)
    at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.createContextual(CollectionDeserializer.java:23)
    at com.fasterxml.jackson.databind.DeserializationContext.findContextualValueDeserializer(DeserializationContext.java:329)
    at com.fasterxml.jackson.databind.deser.impl.PropertyBasedCreator.construct(PropertyBasedCreator.java:96)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.resolve(BeanDeserializerBase.java:406)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:295)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:244)
    at com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:143)
    at com.fasterxml.jackson.databind.DeserializationContext.findRootValueDeserializer(DeserializationContext.java:342)
    at com.fasterxml.jackson.databind.ObjectMapper._findRootDeserializer(ObjectMapper.java:2898)
    at com.fasterxml.jackson.databind.ObjectMapper._readValue(ObjectMapper.java:2763)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:1477)
    at com.fasterxml.jackson.core.JsonParser.readValueAs(JsonParser.java:1285)

This exception does not happen with versions of jackson-databind prior to 2.1.0. I've tested with versions: 2.0.2, 2.0.4, 2.0.5, 2.0.6.

Let me know if you need more information.

@cowtowncoder
Copy link
Member

This is not much information to go about. Do you have actual exception message, indicating which Java type triggers this? Presumably it is a class that uses @JsonCreator (due to line number).

@ihr
Copy link
Author

ihr commented Nov 19, 2012

I don't have actual exception message. But from debugging I gather it's the root class of my hierarchy which is abstract. Let me know if there is something else you would like to know.

@cowtowncoder
Copy link
Member

Could you share the root object? To fix this, I will need to be able to reproduce it, and at this point I can't.
Unit test would be ideal; there is something special about either your configuration, or class definitions, that causes this.

@ihr
Copy link
Author

ihr commented Nov 19, 2012

Here you go: https://gist.github.com/4113543

@cowtowncoder
Copy link
Member

Thanks!

@cowtowncoder
Copy link
Member

Ok. Use of creator methods may be problematic with polymorphic types, so although this should work, a temporary work-around would be to change 'id' to be passed via field or (private) setter.

@cowtowncoder
Copy link
Member

I added a check to at least indicate the root cause ("could not find creator property with name 'id'") here, as the first step.

@ihr
Copy link
Author

ihr commented Nov 22, 2012

Great. Do you plan to correct this problem for the next release?

@cowtowncoder
Copy link
Member

If possible yes, i.e. my best intention is to do that. But it all depends on what exactly is going on.

I would recommend however to work around the issue in the meantime by moving id not to be passed via creator. I suspect that combination (abstract types, creator methods) is triggering the issue.

@jacques-n
Copy link

Another workaround for this issue is to ensure that you use an interface as the base rather than an abstract class. Then decorate the interface with @JsonTypeInfo.

@chids
Copy link

chids commented Mar 5, 2013

I bumped in to this when playing around with code along the lines of:

public class DummyTest {
    @Test
    public void test() throws JsonParseException, JsonMappingException, IOException {
        new ObjectMapper()
                .setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE)
                .readValue("{\"foo\":\"blah\",\"bar\":\"bleh\"}", Sample.class);
    }

    public static class Sample {
        @JsonProperty
        private String foo;

        @JsonProperty
        private String bar;

        public Sample(@JsonProperty("foo") String foo, @JsonProperty("bar") String bar) {
            this.bar = bar;
            this.foo = foo;
        }
    }
}

@cowtowncoder
Copy link
Member

@chids What problem are you seeing here? This should just work fine, as there is no polymorphic type to consider?

@chids
Copy link

chids commented Mar 5, 2013

@cowtowncoder I stumbled on a NPE in BeanDeserializerFactory (matching the one originally reported in this issue) while "tweaking" the ObjectMapper-configuration in a Dropwizard service. I tried to reproduce it by cloning jackson-databind and putting in the test case above just to see whether it'd been fixed in master. Instead of NPE I get could not find creator property with name 'id' and tracked that to your comment above.

From my, somewhat narrow, point of view the culprit seems to be:
setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE)

But I also noticed that the error went away if I removed any one of the constructor arguments in the code above (thus leaving the constructor with only one argument).

@cowtowncoder
Copy link
Member

@chids: handling of a single-non-annotated-ctor-argument is different: this will be considered so-called "delegating" creator, meaning that Jackson will actually bind full matching value and pass that; whereas with named parameters, JSON content must be a JSON Object, and properties are extracted from that. So your work-around does change semantics of handling.

You are right in that if auto-discovery is disabled, it has effect on handling of constructors that could otherwise be located as per rules (single-String, single-int/long/Integer/Long constructors).

So: to fix your example, you must add @JsonCreator next to constructor, since otherwise it will be ignored due to disabling of creator auto-detection. No attempt is made to try to look into parameter annotations; only explicit annotation on methods/fields/constructors are used.

@cowtowncoder
Copy link
Member

Oh. Actually, one more thing: delegating-constructor should also NOT be auto-detected, with your configuration. So there may be a small flaw in there.

@chids
Copy link

chids commented Mar 14, 2013

@cowtowncoder ok, thanks!

@cowtowncoder
Copy link
Member

With 2.3.0-SNAPSHOT error now becomes:

com.fasterxml.jackson.databind.JsonMappingException: Could not find creator property with name 'id' (in class com.fasterxml.jackson.failing.TestIssueGH113$Animal)
at [Source: java.io.StringReader@671381e7; line: 1, column: 1]

which suggests that combination of polymorphic types and creator methods has its issues still.

cowtowncoder added a commit that referenced this issue Sep 13, 2013
@jojenki
Copy link

jojenki commented Nov 13, 2013

Bump. (Also, I just found a workaround, but there still seems to be some bug here.)

http://stackoverflow.com/questions/19941155/jsontypeinfo-is-broken-when-subclasses-have-members-and-the-root-class-is-a-memb

@cowtowncoder
Copy link
Member

Thank you for adding the link -- hope this helps until we can find a better solution.

@cowtowncoder cowtowncoder added this to the 2.5.0 milestone Sep 26, 2014
@cowtowncoder
Copy link
Member

Ha. Turns out fix was easy; just needed to block handling of creator properties for non-concrete types. Exception came from handler of abstract base type, where handling itself is completely unnecessary.

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

5 participants