question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Existing property polymorphic deserialization does not work on enums

See original GitHub issue

Seems like, enum-related deserialization annotations doesn’t work on polymorphic types with builders. Using the following main:

        ObjectMapper om = new ObjectMapper();
        String json = "{\"type\":\"ggwp\",\"name\":\"Hello\"}";
        Endpoint endpoint = om.readValue( json, Endpoint.class );
        System.out.println(endpoint);

This fails to deserialize due to the non-null requirement of Endpoint#type().

Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of io.toro.integrate.labs.esb1271.AutoValue_EndpointImpl$Builder, problem: Missing required properties: type
 at [Source: {"type":"ggwp","name":"Hello"}; line: 1, column: 30]
	at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:277)
	at com.fasterxml.jackson.databind.DeserializationContext.instantiationException(DeserializationContext.java:1441)
	at com.fasterxml.jackson.databind.DeserializationContext.handleInstantiationProblem(DeserializationContext.java:1055)
...

I tried to set breakpoints to:

  • @JsonCreator Endpoint.Type#fromKey - would’ve expected this to be used, so that proper fallback is taken care of
  • @JsonValue Endpoint.Type#getKey
  • @JsonCreator EndpointImpl.Builder#create - would’ve expected this to be used, so that the type be initialized

…and none of these methods are called. My goal was to deserialize all unknown endpoints into an EndpointImpl, with type = Type.UNRECOGNIZED. I even tried to implement custom JsonSerializer and JsonDeserializer for the enum, but both aren’t called either. I’m using jackson 2.8.6, with google’s auto value.

Edit: Actually, even if I specify an existing ‘type’ in the json, it’s not deserialized properly too.


Here’s the base class:

@JsonTypeInfo(
        use = JsonTypeInfo.Id.NAME,
        include = JsonTypeInfo.As.EXISTING_PROPERTY,
        property = "type",
        defaultImpl = EndpointImpl.class )
@JsonSubTypes( value = {} ) // more subtypes
public abstract class Endpoint {

    @JsonProperty( "name" ) public abstract String name();
    @JsonProperty( "type" ) public abstract Type type();

    public abstract static class Builder<B extends Builder<B>> {
        @JsonProperty( "name" ) public abstract B name( String name );
        @JsonProperty( "type" ) public abstract B type( Type type );
        public abstract Endpoint build();
    }

    public static enum Type {

        UNRECOGNIZED( "unrecognized" );
        ...
        @JsonCreator
        public static Type fromKey( String key ) {
            for ( Type type : values() ) {
                if ( type.key.equals( key ) )
                    return type;
            }
            return UNRECOGNIZED;
        }

        @JsonValue
        public String getKey() {
            return key;
        }
    }
}

This is extended by:

@AutoValue
@JsonDeserialize( builder = AutoValue_EndpointImpl.Builder.class )
public abstract class EndpointImpl extends Endpoint {

    public static Builder builder() {
        return new AutoValue_EndpointImpl.Builder()
                        .type( Type.UNRECOGNIZED );
    }

    @AutoValue.Builder
    public abstract static class Builder extends Endpoint.Builder<Builder> {

        @JsonCreator
        private static Builder create() {
            return EndpointImpl.builder();
        }

        public abstract EndpointImpl build();
    }

}

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Comments:9 (7 by maintainers)

github_iconTop GitHub Comments

1reaction
cowtowncodercommented, Jun 11, 2017

Ah. One problem with code as shown: @JsonTypeInfo must specify property visible:

visible=true

for type id to be exposed to regular BeanDeserializer, which can then map it to existing property. Without this, type id is considered metadata, consumed directly by databind itself. This is the default setting.

The reason why visibility is not directly determine from EXISTING_PROPERTY (which would seem like a reasonable inference) is that there are couple of different uses for existing-property option: one being it would only be accessed via getter (or field) for serialization; but not necessarily set during deserialization.

So, this needs to be added. With this setting, both String and enum-valued type id property does get property set, in a more simplified test I’ll add.

It does however look that this is not enough for your test case, so I will try digging deeper; it is possible that use of Creator properties could be the problem here, or that it is due to use as defaultImpl.

0reactions
cowtowncodercommented, Oct 9, 2020

At this point, I am not sure quite how to reproduce the issue and handling may have changed significantly over past 3 years. Closing now, may be re-filed with a simplified reproduction.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Jackson Polymorphic Deserialization based on Enum
I'm working with JacksonPolymorphicDeserialization, this is my code which deserializes into the proper class based in the 'type' property:
Read more >
Polymorphic deserialization with Jackson and no annotations
Problem. If we go directly invoking the /players endpoint, we'll face the InvalidDefinitionException as Jackson can't define to which class ...
Read more >
Migrate from Newtonsoft.Json to System.Text.Json - .NET
Json has several ways to conditionally ignore a property on serialization or deserialization: DefaultContractResolver lets you select properties ...
Read more >
How To Serialize and Deserialize Enums with Jackson
In this quick tutorial, we'll learn how to control the way Java Enums are serialized and deserialized with Jackson 2.
Read more >
Enum DeserializationFeature - Adobe Developer
Feature that determines whether encountering of unknown properties (ones that do not map to a property, and there is no "any setter" or...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found