gwt-jackson icon indicating copy to clipboard operation
gwt-jackson copied to clipboard

Support @JsonCreator for enum classes

Open kukido opened this issue 8 years ago • 6 comments

Hi! We would like to add support for @JsonCreator annotations in our enumerations. What would be the best way to approach that?

kukido avatar Jul 17 '17 17:07 kukido

I didn't know that was possible!
What's the use case ?

nmorel avatar Jul 19 '17 07:07 nmorel

I added a PR with a test case. SO discussion: https://stackoverflow.com/questions/12468764/jackson-enum-serializing-and-deserializer

A workaround would be to have a custom deserializer for enum type. It works as expected.

kukido avatar Jul 19 '17 16:07 kukido

Was this ever addressed?

As we were unaware of the limitations of JsonCreator on an enum and unfortunately have used code similar to the below

    @JsonCreator
    public static MyEnum parse(String value) {
        for(final MyEnum me : values()) {
            if(me.getSomeValue() == value) {
                return me;
            }
        }
        Log.error("Unknown MyEnum:", value);
        return UNKNOWN;
    }

The main part here is we return UNKNOWN, which is the default value of the enum, if the value coming from the server does not match an enum we have in the system.

We thought @JsonCreator would be our saviour. We thought it had been tested and passed, but I guess we forgot to try "value that the enum doesn't have" and now running into problems.

I have read about putting a custom deserialiser to get around this, but not seen anything about putting a custom deserialiser on an enum anywhere.

WORMSS avatar Jan 30 '18 19:01 WORMSS

We decided to use a workaround, considering a number of enumerations affected.

Here's what you need for the workaround:

Enumeration JSON deserializer

public class GwtCapabilityDeserializer extends JsonDeserializer<Capability> {

    private static final GwtCapabilityDeserializer INSTANCE = new GwtCapabilityDeserializer();

    /**
     * @return an instance of {@link GwtCapabilityDeserializer}
     */
    public static GwtCapabilityDeserializer getInstance() {
        return INSTANCE;
    }

    private GwtCapabilityDeserializer() {
    }

    @Override
    protected Capability doDeserialize(JsonReader reader, JsonDeserializationContext ctx, JsonDeserializerParameters params) {
        return Capability.fromString(reader.nextString());
    }
}

Key Enumeration JSON Deserializer (optional)

public class GwtProviderTypeKeyDeserializer extends KeyDeserializer<ProviderType> {

    private static final GwtProviderTypeKeyDeserializer INSTANCE = new GwtProviderTypeKeyDeserializer();

    /**
     * @return an instance of {@link GwtProviderTypeKeyDeserializer}
     */
    public static GwtProviderTypeKeyDeserializer getInstance() {
        return INSTANCE;
    }

    private GwtProviderTypeKeyDeserializer() {
    }

    @Override
    protected ProviderType doDeserialize(String key, JsonDeserializationContext ctx) {
        return ProviderType.get(key);
    }
}

CustomDeserializersConfiguration

import com.github.nmorel.gwtjackson.client.AbstractConfiguration;

public class CustomDeserializersConfiguration extends AbstractConfiguration {
    @Override
    protected void configure() {
        // types
        type(Capability.class).deserializer(GwtCapabilityDeserializer.class);

        // keys
        key(ProviderType.class).deserializer(GwtProviderTypeKeyDeserializer.class);
    }
}

Update gwt module

<module>
    <!-- gwt-jackson dependency -->
    <inherits name="com.github.nmorel.gwtjackson.GwtJackson"/>
    <inherits name="com.github.nmorel.gwtjackson.guava.GwtJacksonGuava" />

    <!-- custom deserializers for gwt-jackson -->
    <extend-configuration-property name="gwtjackson.configuration.extension" value="com.example.gwt.serde.CustomDeserializersConfiguration" />
</module>

kukido avatar Feb 02 '18 21:02 kukido

Ok, when I am back at work on Monday, I will need to give it a try.. But I will admit, I have No idea what any of the code above does or how to use it.

WORMSS avatar Feb 02 '18 23:02 WORMSS

Is there any update on this? I pulled in 0.15.4 to my project but it seems like enums with a static @JsonCreator method are still using the standard enum deserializer. I know it's possible to write a custom one deserializer (and have done so), but would prefer to use the methods specified by our generated model.

isorashi avatar Nov 02 '18 20:11 isorashi