Polymorphism through a typeId from within a nested object

1,869 views
Skip to first unread message

Julien May

unread,
Jul 31, 2015, 6:36:12 PM7/31/15
to jackson-user
Hi there

I am having a json equal to:

{
"bars" : [
{
"foo" : {

},
"baz" : "..."

},

{
"foo" : {
"href" : "http://example.com/types/b"

},
"qux" : "..."

}
]
}

and some java classes like:

public static class Gna {
    @JsonProperty("bars")
    public List<Bar> bars;
}

public static class Foo {
    @JsonProperty("href")
    public String href;
}

@JsonTypeInfo(use = JsonTypeInfo.Id.CUSTOM, include= JsonTypeInfo.As.PROPERTY, property="foo")
@JsonTypeIdResolver(BaseResolver.class)
public static abstract class BaseType {
    @JsonProperty("foo")
    public Foo foo;
}

public static class Baz extends
BaseType {
    @JsonProperty("baz")
    public String baz;
}

public static class Qux extends
BaseType {
    @JsonProperty("qux")
    public String qux;
}


public static class BaseTypeResolver implements TypeIdResolver {
    ...
    @Override
    public JavaType typeFromId(String s) {
        // Here i get "{"
        ...
    }
    ...
}

Trying to deserialize the above json to fails with the exception:

Unexpected token (END_OBJECT), expected FIELD_NAME: missing property 'foo' that is to contain type id  (for class BaseType)
 at [Source: N/A; line: -1, column: -1] (through reference chain: Gna["bars"]->java.util.ArrayList[0])

It is clear to me that i somehow have to point to the "href" attribute within Foo but it is not clear to me how i can do that. Is that even supported through JsonTypeInfo?

According to the documentation (http://wiki.fasterxml.com/JacksonPolymorphicDeserialization#line-120) it should be possible with the use of the @JsonTypeResolver.

If the reference of a typeid cannot be taken from within a nested object, is there a somehow alternative elegant way to achieve this? Writing a custom deserializer
seems like a quiet bad solution to me.

Thanks for helping
rgds julien

Tatu Saloranta

unread,
Jul 31, 2015, 7:43:19 PM7/31/15
to jackso...@googlegroups.com
In general, type id really needs to be a JSON String, and not a structured value like JSON Object.
This is what @JsonTypeInfo supports, with various inclusion mechanisms (as-property, like in your case; as a wrapper Object; as a wrapper Array with type id as first element; as "external" property within parent object).
There is no support for using structured values, nor any plans to directly support them.

However; perhaps it would be possible to use a "delegating" style deserializer to first bind JSON into an intermediate form (like JsonNode or java.util.Map); and then let Converter figure out type of object to deserialize into (and probably remove type identifier), find deserializer for that type, and feed content to it (JsonNode can be read as stream of tokens, that is, can get JsonParser out of it).

This sounds complicated, but it should be possible by either extending StdDelegatingDeserializer; or using

@JsonDeserialize(converter=MyConverter.class)

on property/-ies that would use conversion mechanism.

-+ Tatu +-


--
You received this message because you are subscribed to the Google Groups "jackson-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jackson-user...@googlegroups.com.
To post to this group, send email to jackso...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply all
Reply to author
Forward
0 new messages