From 8d6c35d5ccfe21668fdcd2bb0730edb5cda9cabf Mon Sep 17 00:00:00 2001 From: Peter Jurkovic Date: Mon, 4 Dec 2017 01:04:22 +0000 Subject: [PATCH] ClassNameIdResolver doesn't handle resolve Collections$SingletonMap & Collections$SingletonSet (#1823) Fix ClassNameIdResolver - support for Set and Map collections --- .../jsontype/impl/ClassNameIdResolver.java | 27 ++++--- .../impl/ClassNameIdResolverTest.java | 74 +++++++++++++++++++ 2 files changed, 91 insertions(+), 10 deletions(-) create mode 100644 src/test/java/com/fasterxml/jackson/databind/jsontype/impl/ClassNameIdResolverTest.java diff --git a/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/ClassNameIdResolver.java b/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/ClassNameIdResolver.java index d93b8cada3..1cb8ae276e 100644 --- a/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/ClassNameIdResolver.java +++ b/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/ClassNameIdResolver.java @@ -61,7 +61,7 @@ protected JavaType _typeFromId(String id, DatabindContext ctxt) throws IOExcepti /********************************************************** */ - protected final String _idFrom(Object value, Class cls, TypeFactory typeFactory) + protected String _idFrom(Object value, Class cls, TypeFactory typeFactory) { // Need to ensure that "enum subtypes" work too if (Enum.class.isAssignableFrom(cls)) { @@ -87,16 +87,18 @@ protected final String _idFrom(Object value, Class cls, TypeFactory typeFacto // not optimal: but EnumMap is not a customizable type so this is sort of ok str = typeFactory.constructMapType(EnumMap.class, enumClass, valueClass).toCanonical(); } else { - String end = str.substring(9); - if ((end.startsWith(".Arrays$") || end.startsWith(".Collections$")) - && str.indexOf("List") >= 0) { - /* 17-Feb-2010, tatus: Another such case: result of - * Arrays.asList() is named like so in Sun JDK... - * Let's just plain old ArrayList in its place - * NOTE: chances are there are plenty of similar cases - * for other wrappers... (immutable, singleton, synced etc) - */ + /* 17-Feb-2010, tatus: Another such case: result of + * Arrays.asList() is named like so in Sun JDK... + * Let's just plain old ArrayList in its place + * NOTE: chances are there are plenty of similar cases + * for other wrappers... (immutable, singleton, synced etc) + */ + if (isJavaUtilCollectionClass(str, "List")) { str = "java.util.ArrayList"; + }else if(isJavaUtilCollectionClass(str, "Map")){ + str = "java.util.HashMap"; + }else if(isJavaUtilCollectionClass(str, "Set")){ + str = "java.util.HashSet"; } } } else if (str.indexOf('$') >= 0) { @@ -128,4 +130,9 @@ protected final String _idFrom(Object value, Class cls, TypeFactory typeFacto public String getDescForKnownTypeIds() { return "class name used as type id"; } + + private static boolean isJavaUtilCollectionClass(String clazzName, String type){ + String end = clazzName.substring(9); + return (end.startsWith(".Collections$") || end.startsWith(".Arrays$")) && clazzName.indexOf(type) > 0; + } } diff --git a/src/test/java/com/fasterxml/jackson/databind/jsontype/impl/ClassNameIdResolverTest.java b/src/test/java/com/fasterxml/jackson/databind/jsontype/impl/ClassNameIdResolverTest.java new file mode 100644 index 0000000000..5da854d4b6 --- /dev/null +++ b/src/test/java/com/fasterxml/jackson/databind/jsontype/impl/ClassNameIdResolverTest.java @@ -0,0 +1,74 @@ +package com.fasterxml.jackson.databind.jsontype.impl; + +import static org.junit.Assert.assertEquals; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import com.fasterxml.jackson.databind.type.TypeFactory; + +import com.fasterxml.jackson.databind.JavaType; + +@RunWith(PowerMockRunner.class) +@PrepareForTest(TypeFactory.class) +public class ClassNameIdResolverTest { + + @Mock + private JavaType javaType; + + @Mock + private TypeFactory typeFactory; + + + private ClassNameIdResolver classNameIdResolver; + + @Before + public void setup(){ + this.classNameIdResolver = new ClassNameIdResolver(javaType, typeFactory); + } + + @Test + public void testIdFromValue_shouldUseJavaUtilHashMapForSingletonMap(){ + Map singletonMap = Collections.singletonMap("ANY_KEY", "ANY_VALUE"); + + String clazz = classNameIdResolver.idFromValue( singletonMap ); + + assertEquals(clazz, "java.util.HashMap"); + } + + @Test + public void testIdFromValue_shouldUseJavaUtilHashSetForSingletonSet(){ + Set singletonSet = Collections.singleton("ANY_VALUE"); + + String clazz = classNameIdResolver.idFromValue( singletonSet ); + + assertEquals(clazz, "java.util.HashSet"); + } + + @Test + public void testIdFromValue_shouldUseJavaUtilArrayListForSingletonList(){ + List singletonList = Collections.singletonList("ANY_VALUE"); + + String clazz = classNameIdResolver.idFromValue( singletonList ); + + assertEquals(clazz, "java.util.ArrayList"); + } + + @Test + public void testIdFromValue_shouldUseJavaUtilArrayListForArrays$List(){ + List utilList = Arrays.asList("ANY_VALUE"); + + String clazz = classNameIdResolver.idFromValue( utilList ); + + assertEquals(clazz, "java.util.ArrayList"); + } +}