From d1959f88327a6172a527de201a2134afd9aaf01f Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Sun, 29 Sep 2019 10:53:42 -0700 Subject: [PATCH] Fix #2457 (enum subtypes not working as map keys) --- release-notes/CREDITS-2.x | 4 +++ release-notes/VERSION-2.x | 5 +++ .../fasterxml/jackson/databind/JavaType.java | 7 +++- .../databind/ser/std/StdKeySerializers.java | 4 ++- .../deser/jdk/EnumMapDeserializationTest.java | 34 +++++++++++++++++++ 5 files changed, 52 insertions(+), 2 deletions(-) diff --git a/release-notes/CREDITS-2.x b/release-notes/CREDITS-2.x index 3ba4776569..0faa36a5ba 100644 --- a/release-notes/CREDITS-2.x +++ b/release-notes/CREDITS-2.x @@ -971,3 +971,7 @@ Martín Coll (colltoaction@github) * Contributed #2467: Accept `JsonTypeInfo.As.WRAPPER_ARRAY` with no second argument to deserialize as "null value" (2.10.0) + +Andrey Kulikov (ankulikov@github) + * Reported #2457: Extended enum values are not handled as enums when used as Map keys + (2.10.1) diff --git a/release-notes/VERSION-2.x b/release-notes/VERSION-2.x index d7073fe2f3..f3582ea872 100644 --- a/release-notes/VERSION-2.x +++ b/release-notes/VERSION-2.x @@ -4,6 +4,11 @@ Project: jackson-databind === Releases === ------------------------------------------------------------------------ +2.10.1 (not yet released) + +#2457: Extended enum values are not handled as enums when used as Map keys + (reported by Andrey K) + 2.10.0 (26-Sep-2019) #18: Make `JsonNode` serializable diff --git a/src/main/java/com/fasterxml/jackson/databind/JavaType.java b/src/main/java/com/fasterxml/jackson/databind/JavaType.java index 3fdbb2b1f2..fe3cc8fa2a 100644 --- a/src/main/java/com/fasterxml/jackson/databind/JavaType.java +++ b/src/main/java/com/fasterxml/jackson/databind/JavaType.java @@ -288,7 +288,12 @@ public boolean isConcrete() { public boolean isArrayType() { return false; } @Override - public final boolean isEnumType() { return _class.isEnum(); } + public final boolean isEnumType() { + // 29-Sep-2019, tatu: `Class.isEnum()` not enough to detect custom subtypes, + // use this instead +// return Enum.class.isAssignableFrom(_class); + return _class.isEnum(); + } @Override public final boolean isInterface() { return _class.isInterface(); } diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/std/StdKeySerializers.java b/src/main/java/com/fasterxml/jackson/databind/ser/std/StdKeySerializers.java index 408dc54c24..20dae5df3a 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ser/std/StdKeySerializers.java +++ b/src/main/java/com/fasterxml/jackson/databind/ser/std/StdKeySerializers.java @@ -98,7 +98,9 @@ public static JsonSerializer getFallbackKeySerializer(SerializationConfi if (rawKeyType == Enum.class) { return new Dynamic(); } - if (rawKeyType.isEnum()) { + // 29-Sep-2019, tatu: [databind#2457] can not use 'rawKeyType.isEnum()`, won't work + // for subtypes. + if (Enum.class.isAssignableFrom(rawKeyType)) { return EnumKeySerializer.construct(rawKeyType, EnumValues.constructFromName(config, (Class>) rawKeyType)); } diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/jdk/EnumMapDeserializationTest.java b/src/test/java/com/fasterxml/jackson/databind/deser/jdk/EnumMapDeserializationTest.java index 8cdf9afbfb..d458c06709 100644 --- a/src/test/java/com/fasterxml/jackson/databind/deser/jdk/EnumMapDeserializationTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/deser/jdk/EnumMapDeserializationTest.java @@ -1,6 +1,7 @@ package com.fasterxml.jackson.databind.deser.jdk; import java.util.EnumMap; +import java.util.LinkedHashMap; import java.util.Map; import com.fasterxml.jackson.annotation.*; @@ -77,6 +78,22 @@ public Pojo1859(EnumMap v) { } } + // [databind#2457] + enum MyEnum2457 { + A, + B() { + // just to ensure subclass construction + @Override + public void foo() { } + }; + + // needed to force subclassing + public void foo() { } + + @Override + public String toString() { return name() + " as string"; } + } + /* /********************************************************** /* Test methods, basic @@ -224,4 +241,21 @@ public void testUnknownKeyAsNull() throws Exception assertEquals(1, value2.size()); assertEquals("value", value2.get(null)); } + + // [databind#2457] + public void testCustomEnumAsRootMapKey() throws Exception + { + final ObjectMapper mapper = newJsonMapper(); + final Map map = new LinkedHashMap<>(); + map.put(MyEnum2457.A, "1"); + map.put(MyEnum2457.B, "2"); + assertEquals(aposToQuotes("{'A':'1','B':'2'}"), + mapper.writeValueAsString(map)); + + // But should be able to override + assertEquals(aposToQuotes("{'"+MyEnum2457.A.toString()+"':'1','"+MyEnum2457.B.toString()+"':'2'}"), + mapper.writer() + .with(SerializationFeature.WRITE_ENUMS_USING_TO_STRING) + .writeValueAsString(map)); + } }