Search before asking

  • [x] I searched in the issues and found nothing similar.

Describe the bug

EnumDeserializer fails to deserialize Enums with @JsonValue - uses table with name() key instead of @JsonValue key.

The difference between Jackson2 and Jackson3 is the choice of tables used for lookup (see debugger screen-shot).

    @Test
    void convertStringToEnum() {
        assertThat(new ObjectMapper().convertValue("10%", MyEnum.class)).isEqualTo(MyEnum.T10);
    }

    public enum MyEnum {
        T10("10%"), T20("20%"), T30("30%");

        private final String code;

        MyEnum(String code) {
            this.code = code;
        }

        @JsonValue
        public String getCode() {
            return code;
        }
    }
tools.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `org.springframework.data.couchbase.core.mapping.MappingCouchbaseConverterTests$MyEnum` from String "10%": not one of the values accepted for Enum class: [T30, T20, T10]
 at [No location information]

    at tools.jackson.databind.exc.InvalidFormatException.from(InvalidFormatException.java:37)
    at tools.jackson.databind.DeserializationContext.weirdStringException(DeserializationContext.java:1977)
    at tools.jackson.databind.DeserializationContext.handleWeirdStringValue(DeserializationContext.java:1320)
    at tools.jackson.databind.deser.jdk.EnumDeserializer._deserializeAltString(EnumDeserializer.java:355)
    at tools.jackson.databind.deser.jdk.EnumDeserializer._fromString(EnumDeserializer.java:215)
    at tools.jackson.databind.deser.jdk.EnumDeserializer.deserialize(EnumDeserializer.java:184)
    at tools.jackson.databind.ObjectMapper._convert(ObjectMapper.java:2391)
    at tools.jackson.databind.ObjectMapper.convertValue(ObjectMapper.java:2323)

In the debugger

With Jackson3, the lookup table has the name() as the key. Thus it does not find the corresponding Enum.

Image

With Jackson2 the lookup table has the @JsonValue values as the key. It does find the corresponding Enum using the serialized value.

Image

Expected behavior

Test passes.

Additional context

Works in Jackson 2

Comment From: JooHyukKim

Thank you for reporting! Seems like a regression indeed

Comment From: mikereiche

In Jackson3 the (ctx.feature_flags & READ_ENUMS_USING_TO_STRING != 0) == true

00011100110000011110010010100000
00000000100000000000000000000000

in Jackson2, (ctx.feature_flags & READ_ENUMS_USING_TO_STRING !=0 ) == false

01110001000001010010010010010000
00000010000000000000000000000000
    private CompactStringObjectMap _resolveCurrentLookup(DeserializationContext ctxt) {
        if (_lookupByEnumNaming != null) {
            return _lookupByEnumNaming;
        }
        return ctxt.isEnabled(DeserializationFeature.READ_ENUMS_USING_TO_STRING)
            ? _lookupByToString
            : _lookupByName;
    }

Comment From: mikereiche

/**
 * Feature that determines the deserialization mechanism used for
 * Enum values: if enabled, Enums are assumed to have been serialized using
 * return value of {@code Enum.toString()};
 * if disabled, return value of {@code Enum.name()} is assumed to have been used.
 *<p>
 * Note: this feature should usually have same value
 * as {@link SerializationFeature#WRITE_ENUMS_USING_TO_STRING}.
 *<p>
 * Feature is enabled by default as of Jackson 3.0 (in 2.x it was disabled).     <--------------------------------------------
 */
READ_ENUMS_USING_TO_STRING(true),

Comment From: mikereiche

This will fix the enum. But shouldn't it work without it?

@Override String toString(){ return jsonValue(): }

Comment From: pjfanning

In Jackson 3, this has moved to EnumFeature and default has changed.

    /**
     * Feature that determines the deserialization mechanism used for
     * Enum values: if enabled, Enums are assumed to have been serialized using
     * return value of {@code Enum.toString()};
     * if disabled, return value of {@code Enum.name()} is assumed to have been used.
     *<p>
     * Note: this feature should usually have same value
     * as {@link #WRITE_ENUMS_USING_TO_STRING}.
     *<p>
     * Feature used to be one of {@link tools.jackson.databind.DeserializationFeature}s
     * in Jackson 2.x but was moved here in 3.0.
     *<p>
     * Feature is enabled by default as of Jackson 3.0 (in 2.x it was disabled).
     */
    READ_ENUMS_USING_TO_STRING(true),