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.
With Jackson2 the lookup table has the @JsonValue values as the key. It does find the corresponding Enum using the serialized value.
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),