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

@JsonTypeInfo with As.EXTERNAL_PROPERTY doesn't work if external type property is referenced more than once #291

Closed
Starkom opened this issue Aug 26, 2013 · 8 comments
Milestone

Comments

@Starkom
Copy link

Starkom commented Aug 26, 2013

Test model:

    public static interface F1 {}

    public static class A implements F1 {
        public String a;
    }

    public static class B implements F1 {
        public String b;
    }

    public static interface F2 {}

    public static class C implements F2 {
        public String c;
    }

    public static class D implements F2{
        public String d;
    }

    public static class Container {
        public String type;

        @JsonTypeInfo(use = Id.NAME, property = "type", include = As.EXTERNAL_PROPERTY)
        @JsonSubTypes({
                @JsonSubTypes.Type(value = A.class, name = "1"),
                @JsonSubTypes.Type(value = B.class, name = "2")})
        public F1 field1;

        @JsonTypeInfo(use = Id.NAME, property = "type", include = As.EXTERNAL_PROPERTY)
        @JsonSubTypes({
                @JsonSubTypes.Type(value = C.class, name = "1"),
                @JsonSubTypes.Type(value = D.class, name = "2")})
        public F2 field2;
    }

Test JSON:

{
 "type" : "1",
 "field1" : {
   "a" : "AAA"
 },
 "field2" : {
   "c" : "CCC"
 }
}

Stacktrace:

com.fasterxml.jackson.databind.JsonMappingException: Unexpected token (VALUE_NULL), expected VALUE_STRING: need JSON String that contains type id (for subtype of F2)
at [Source: java.io.StringReader@b2fe7658; line: 9, column: 1]
at com.fasterxml.jackson.databind.DeserializationContext.wrongTokenException(DeserializationContext.java:668)
at com.fasterxml.jackson.databind.jsontype.impl.AsArrayTypeDeserializer._locateTypeId(AsArrayTypeDeserializer.java:144)
at com.fasterxml.jackson.databind.jsontype.impl.AsArrayTypeDeserializer._deserialize(AsArrayTypeDeserializer.java:101)
at com.fasterxml.jackson.databind.jsontype.impl.AsArrayTypeDeserializer.deserializeTypedFromObject(AsArrayTypeDeserializer.java:69)
at com.fasterxml.jackson.databind.deser.AbstractDeserializer.deserializeWithType(AbstractDeserializer.java:106)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:462)
at com.fasterxml.jackson.databind.deser.impl.FieldProperty.deserializeAndSet(FieldProperty.java:107)
at com.fasterxml.jackson.databind.deser.impl.ExternalTypeHandler._deserializeAndSet(ExternalTypeHandler.java:253)
at com.fasterxml.jackson.databind.deser.impl.ExternalTypeHandler.complete(ExternalTypeHandler.java:162)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeWithExternalTypeId(BeanDeserializer.java:715)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeWithExternalTypeId(BeanDeserializer.java:664)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:274)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:121)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:2888)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2034)

The reason:

com.fasterxml.jackson.databind.deser.impl.ExternalTypeHandler:262

    public static class Builder
    {
        private final ArrayList<ExtTypedProperty> _properties = new ArrayList<ExtTypedProperty>();
        private final HashMap<String, Integer> _nameToPropertyIndex = new HashMap<String, Integer>();

        // note: signature changed between 2.1.0 and 2.1.1 (alas!)
        public void addExternal(SettableBeanProperty property, TypeDeserializer typeDeser)
        {
            Integer index = _properties.size();
            _properties.add(new ExtTypedProperty(property, typeDeser));
            _nameToPropertyIndex.put(property.getName(), index);
            _nameToPropertyIndex.put(typeDeser.getPropertyName(), index);
        }

addExternal() method is called in property loop, but _nameToPropertyIndex is Map, so addExternal() can't be called twice correctly for property "type".

So _nameToPropertyIndex doesn't contain type=0: {field1=1, type=1, field2=0}

I think type of _nameToPropertyIndex should be changed from HashMap[String, Integer] to HashMap[String, Set[Integer]]. It occurs several changes in ExternalTypeHandler. I've patched jar locally and it solved my problem.

@cowtowncoder
Copy link
Member

Hmmh. This isn't actually a use case I was familiar with (or design to support)... but ok, if it can be supported, all the better. :)

@dvdh
Copy link

dvdh commented Sep 25, 2014

@cowtowncoder is this a supported use case now?

@cowtowncoder
Copy link
Member

@dvdh No changes have been made, and it is unlikely I will have time to work on this in near future. So no.

@dvdh
Copy link

dvdh commented Sep 25, 2014

Thanks @cowtowncoder

@ABHINAVKR
Copy link

As suggested by @Starkom i have done the changes , but two tests are failing after those changes.

Failed tests:
TestExternalId.testIssue798:376 null
Tests in error:
TestExternalId.testInverseExternalId928:505 NullPointer
Tests run: 1513, Failures: 1, Errors: 1, Skipped: 0

Any suggestions @cowtowncoder for fixing these TESTS

@cowtowncoder
Copy link
Member

@ABHINAVKR you would need bit more context (stack traces). And also know which Jackson versions they are for.

@cowtowncoder
Copy link
Member

Seems fixable; ideally would avoid use of Set, but perhaps could use Collections.singleton() for the common case of just a single id. Most likely fixing for 2.9, to minimize risk of regression.

@cowtowncoder cowtowncoder added this to the 2.9.0 milestone Nov 29, 2016
@cowtowncoder
Copy link
Member

Finally found time to fix this; also improved testing a bit to cover other cases (differently ordered input, with and without additional type property).

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

4 participants