diff --git a/gson/src/main/java/com/google/gson/internal/ConstructorConstructor.java b/gson/src/main/java/com/google/gson/internal/ConstructorConstructor.java index 62bae91c..6fc9f2d3 100644 --- a/gson/src/main/java/com/google/gson/internal/ConstructorConstructor.java +++ b/gson/src/main/java/com/google/gson/internal/ConstructorConstructor.java @@ -16,10 +16,6 @@ package com.google.gson.internal; -import com.google.gson.InstanceCreator; -import com.google.gson.JsonIOException; -import com.google.gson.reflect.TypeToken; - import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.ParameterizedType; @@ -37,6 +33,14 @@ import java.util.SortedMap; import java.util.SortedSet; import java.util.TreeMap; import java.util.TreeSet; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ConcurrentNavigableMap; +import java.util.concurrent.ConcurrentSkipListMap; + +import com.google.gson.InstanceCreator; +import com.google.gson.JsonIOException; +import com.google.gson.reflect.TypeToken; /** * Returns a function that can construct an instance of a requested type. @@ -58,7 +62,7 @@ public final class ConstructorConstructor { final InstanceCreator typeCreator = (InstanceCreator) instanceCreators.get(type); if (typeCreator != null) { return new ObjectConstructor() { - public T construct() { + @Override public T construct() { return typeCreator.createInstance(type); } }; @@ -70,7 +74,7 @@ public final class ConstructorConstructor { (InstanceCreator) instanceCreators.get(rawType); if (rawTypeCreator != null) { return new ObjectConstructor() { - public T construct() { + @Override public T construct() { return rawTypeCreator.createInstance(type); } }; @@ -98,7 +102,7 @@ public final class ConstructorConstructor { } return new ObjectConstructor() { @SuppressWarnings("unchecked") // T is the same raw type as is requested - public T construct() { + @Override public T construct() { try { Object[] args = null; return (T) constructor.newInstance(args); @@ -130,14 +134,14 @@ public final class ConstructorConstructor { if (Collection.class.isAssignableFrom(rawType)) { if (SortedSet.class.isAssignableFrom(rawType)) { return new ObjectConstructor() { - public T construct() { + @Override public T construct() { return (T) new TreeSet(); } }; } else if (EnumSet.class.isAssignableFrom(rawType)) { return new ObjectConstructor() { @SuppressWarnings("rawtypes") - public T construct() { + @Override public T construct() { if (type instanceof ParameterizedType) { Type elementType = ((ParameterizedType) type).getActualTypeArguments()[0]; if (elementType instanceof Class) { @@ -152,19 +156,19 @@ public final class ConstructorConstructor { }; } else if (Set.class.isAssignableFrom(rawType)) { return new ObjectConstructor() { - public T construct() { + @Override public T construct() { return (T) new LinkedHashSet(); } }; } else if (Queue.class.isAssignableFrom(rawType)) { return new ObjectConstructor() { - public T construct() { + @Override public T construct() { return (T) new LinkedList(); } }; } else { return new ObjectConstructor() { - public T construct() { + @Override public T construct() { return (T) new ArrayList(); } }; @@ -172,22 +176,34 @@ public final class ConstructorConstructor { } if (Map.class.isAssignableFrom(rawType)) { - if (SortedMap.class.isAssignableFrom(rawType)) { + if (ConcurrentNavigableMap.class.isAssignableFrom(rawType)) { return new ObjectConstructor() { - public T construct() { + @Override public T construct() { + return (T) new ConcurrentSkipListMap(); + } + }; + } else if (ConcurrentMap.class.isAssignableFrom(rawType)) { + return new ObjectConstructor() { + @Override public T construct() { + return (T) new ConcurrentHashMap(); + } + }; + } else if (SortedMap.class.isAssignableFrom(rawType)) { + return new ObjectConstructor() { + @Override public T construct() { return (T) new TreeMap(); } }; } else if (type instanceof ParameterizedType && !(String.class.isAssignableFrom( TypeToken.get(((ParameterizedType) type).getActualTypeArguments()[0]).getRawType()))) { return new ObjectConstructor() { - public T construct() { + @Override public T construct() { return (T) new LinkedHashMap(); } }; } else { return new ObjectConstructor() { - public T construct() { + @Override public T construct() { return (T) new LinkedTreeMap(); } }; @@ -202,7 +218,7 @@ public final class ConstructorConstructor { return new ObjectConstructor() { private final UnsafeAllocator unsafeAllocator = UnsafeAllocator.create(); @SuppressWarnings("unchecked") - public T construct() { + @Override public T construct() { try { Object newInstance = unsafeAllocator.newInstance(rawType); return (T) newInstance; diff --git a/gson/src/test/java/com/google/gson/functional/MapTest.java b/gson/src/test/java/com/google/gson/functional/MapTest.java index c175bae5..590760cb 100755 --- a/gson/src/test/java/com/google/gson/functional/MapTest.java +++ b/gson/src/test/java/com/google/gson/functional/MapTest.java @@ -16,6 +16,18 @@ package com.google.gson.functional; +import java.lang.reflect.Type; +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.SortedMap; +import java.util.TreeMap; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ConcurrentNavigableMap; +import java.util.concurrent.ConcurrentSkipListMap; + import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.InstanceCreator; @@ -33,14 +45,6 @@ import com.google.gson.reflect.TypeToken; import junit.framework.TestCase; -import java.lang.reflect.Type; -import java.util.Collection; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.SortedMap; -import java.util.TreeMap; - /** * Functional test for Json serialization and deserialization for Maps * @@ -179,6 +183,46 @@ public class MapTest extends TestCase { assertEquals("456", map.get(123)); } + public void testConcurrentMap() throws Exception { + Type typeOfMap = new TypeToken>() {}.getType(); + ConcurrentMap map = gson.fromJson("{\"123\":\"456\"}", typeOfMap); + assertEquals(1, map.size()); + assertTrue(map.containsKey(123)); + assertEquals("456", map.get(123)); + String json = gson.toJson(map); + assertEquals("{\"123\":\"456\"}", json); + } + + public void testConcurrentHashMap() throws Exception { + Type typeOfMap = new TypeToken>() {}.getType(); + ConcurrentHashMap map = gson.fromJson("{\"123\":\"456\"}", typeOfMap); + assertEquals(1, map.size()); + assertTrue(map.containsKey(123)); + assertEquals("456", map.get(123)); + String json = gson.toJson(map); + assertEquals("{\"123\":\"456\"}", json); + } + + public void testConcurrentNavigableMap() throws Exception { + Type typeOfMap = new TypeToken>() {}.getType(); + ConcurrentNavigableMap map = gson.fromJson("{\"123\":\"456\"}", typeOfMap); + assertEquals(1, map.size()); + assertTrue(map.containsKey(123)); + assertEquals("456", map.get(123)); + String json = gson.toJson(map); + assertEquals("{\"123\":\"456\"}", json); + } + + public void testConcurrentSkipListMap() throws Exception { + Type typeOfMap = new TypeToken>() {}.getType(); + ConcurrentSkipListMap map = gson.fromJson("{\"123\":\"456\"}", typeOfMap); + assertEquals(1, map.size()); + assertTrue(map.containsKey(123)); + assertEquals("456", map.get(123)); + String json = gson.toJson(map); + assertEquals("{\"123\":\"456\"}", json); + } + public void testParameterizedMapSubclassSerialization() { MyParameterizedMap map = new MyParameterizedMap(10); map.put("a", "b");