Add support for wildcard type on Maps, Collections and other parameterized types.
This commit is contained in:
parent
8e1c6a2b37
commit
fc65667d2f
@ -70,6 +70,7 @@ final class ParameterizedTypeHandlerMap<T> {
|
|||||||
rawType = ((ParameterizedType)type).getRawType();
|
rawType = ((ParameterizedType)type).getRawType();
|
||||||
handler = map.get(rawType);
|
handler = map.get(rawType);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for map or collection
|
// Check for map or collection
|
||||||
if (handler == null) {
|
if (handler == null) {
|
||||||
if (rawType instanceof Class) {
|
if (rawType instanceof Class) {
|
||||||
@ -87,13 +88,20 @@ final class ParameterizedTypeHandlerMap<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private synchronized T getRawHandlerFor(Type type) {
|
private synchronized T getRawHandlerFor(Type type) {
|
||||||
T handler = map.get(type);
|
|
||||||
if (type instanceof Map) {
|
if (type instanceof Map) {
|
||||||
handler = map.get(Map.class);
|
return map.get(Map.class);
|
||||||
} else if (type instanceof Collection) {
|
} else if (type instanceof Collection) {
|
||||||
handler = map.get(Collection.class);
|
return map.get(Collection.class);
|
||||||
|
} else {
|
||||||
|
T handler = map.get(type);
|
||||||
|
if (handler == null) {
|
||||||
|
Class<?> rawClass = TypeUtils.toRawClass(type);
|
||||||
|
if (rawClass != type) {
|
||||||
|
handler = getHandlerFor(rawClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return handler;
|
||||||
}
|
}
|
||||||
return handler;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized boolean hasAnyHandlerFor(Type type) {
|
public synchronized boolean hasAnyHandlerFor(Type type) {
|
||||||
|
@ -20,6 +20,7 @@ import java.lang.reflect.Array;
|
|||||||
import java.lang.reflect.GenericArrayType;
|
import java.lang.reflect.GenericArrayType;
|
||||||
import java.lang.reflect.ParameterizedType;
|
import java.lang.reflect.ParameterizedType;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
|
import java.lang.reflect.WildcardType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility class containing some methods for obtaining information on types.
|
* Utility class containing some methods for obtaining information on types.
|
||||||
@ -75,6 +76,9 @@ final class TypeUtils {
|
|||||||
GenericArrayType actualType = (GenericArrayType) type;
|
GenericArrayType actualType = (GenericArrayType) type;
|
||||||
Class<?> rawClass = toRawClass(actualType.getGenericComponentType());
|
Class<?> rawClass = toRawClass(actualType.getGenericComponentType());
|
||||||
return wrapWithArray(rawClass);
|
return wrapWithArray(rawClass);
|
||||||
|
} else if (type instanceof WildcardType) {
|
||||||
|
WildcardType castedType = (WildcardType) type;
|
||||||
|
return toRawClass(castedType.getUpperBounds()[0]);
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("Type \'" + type + "\' is not a Class, "
|
throw new IllegalArgumentException("Type \'" + type + "\' is not a Class, "
|
||||||
+ "ParameterizedType, or GenericArrayType. Can't extract class.");
|
+ "ParameterizedType, or GenericArrayType. Can't extract class.");
|
||||||
|
@ -29,6 +29,7 @@ import java.lang.reflect.Type;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -245,6 +246,44 @@ public class CollectionTest extends TestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testWildcardPrimitiveCollectionSerilaization() throws Exception {
|
||||||
|
Collection<? extends Integer> target = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
|
||||||
|
Type collectionType = new TypeToken<Collection<? extends Integer>>() { }.getType();
|
||||||
|
String json = gson.toJson(target, collectionType);
|
||||||
|
assertEquals("[1,2,3,4,5,6,7,8,9]", json);
|
||||||
|
|
||||||
|
json = gson.toJson(target);
|
||||||
|
assertEquals("[1,2,3,4,5,6,7,8,9]", json);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testWildcardPrimitiveCollectionDeserilaization() throws Exception {
|
||||||
|
String json = "[1,2,3,4,5,6,7,8,9]";
|
||||||
|
Type collectionType = new TypeToken<Collection<? extends Integer>>() { }.getType();
|
||||||
|
Collection<? extends Integer> target = gson.fromJson(json, collectionType);
|
||||||
|
assertEquals(9, target.size());
|
||||||
|
assertTrue(target.contains(1));
|
||||||
|
assertTrue(target.contains(9));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testWildcardCollectionField() throws Exception {
|
||||||
|
Collection<BagOfPrimitives> collection = new ArrayList<BagOfPrimitives>();
|
||||||
|
BagOfPrimitives objA = new BagOfPrimitives(3L, 1, true, "blah");
|
||||||
|
BagOfPrimitives objB = new BagOfPrimitives(2L, 6, false, "blahB");
|
||||||
|
collection.add(objA);
|
||||||
|
collection.add(objB);
|
||||||
|
|
||||||
|
ObjectWithWildcardCollection target = new ObjectWithWildcardCollection(collection);
|
||||||
|
String json = gson.toJson(target);
|
||||||
|
assertTrue(json.contains(objA.getExpectedJson()));
|
||||||
|
assertTrue(json.contains(objB.getExpectedJson()));
|
||||||
|
|
||||||
|
target = gson.fromJson(json, ObjectWithWildcardCollection.class);
|
||||||
|
Collection<? extends BagOfPrimitives> deserializedCollection = target.getCollection();
|
||||||
|
assertEquals(2, deserializedCollection.size());
|
||||||
|
assertTrue(deserializedCollection.contains(objA));
|
||||||
|
assertTrue(deserializedCollection.contains(objB));
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private static int[] toIntArray(Collection collection) {
|
private static int[] toIntArray(Collection collection) {
|
||||||
int[] ints = new int[collection.size()];
|
int[] ints = new int[collection.size()];
|
||||||
@ -259,4 +298,21 @@ public class CollectionTest extends TestCase {
|
|||||||
}
|
}
|
||||||
return ints;
|
return ints;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class ObjectWithWildcardCollection {
|
||||||
|
private final Collection<? extends BagOfPrimitives> collection;
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public ObjectWithWildcardCollection() {
|
||||||
|
this(Collections.EMPTY_LIST);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObjectWithWildcardCollection(Collection<? extends BagOfPrimitives> collection) {
|
||||||
|
this.collection = collection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<? extends BagOfPrimitives> getCollection() {
|
||||||
|
return collection;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
package com.google.gson.functional;
|
package com.google.gson.functional;
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@ -162,7 +163,7 @@ public class MapTest extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void disable_testMapSubclassDeserialization() {
|
public void disable_testMapSubclassDeserialization() {
|
||||||
Gson gson = new GsonBuilder().registerTypeAdapter(MyMap.class, new InstanceCreator<MyMap>(){
|
Gson gson = new GsonBuilder().registerTypeAdapter(MyMap.class, new InstanceCreator<MyMap>() {
|
||||||
public MyMap createInstance(Type type) {
|
public MyMap createInstance(Type type) {
|
||||||
return new MyMap();
|
return new MyMap();
|
||||||
}
|
}
|
||||||
@ -173,6 +174,25 @@ public class MapTest extends TestCase {
|
|||||||
assertEquals("2", map.get("b"));
|
assertEquals("2", map.get("b"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testMapSerializationWithWildcardValues() {
|
||||||
|
Map<String, ? extends Collection<? extends Integer>> map =
|
||||||
|
new LinkedHashMap<String, Collection<Integer>>();
|
||||||
|
map.put("test", null);
|
||||||
|
Type typeOfMap =
|
||||||
|
new TypeToken<Map<String, ? extends Collection<? extends Integer>>>() {}.getType();
|
||||||
|
String json = gson.toJson(map, typeOfMap);
|
||||||
|
|
||||||
|
assertEquals("{}", json);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMapDeserializationWithWildcardValues() {
|
||||||
|
Type typeOfMap = new TypeToken<Map<String, ? extends Long>>() {}.getType();
|
||||||
|
Map<String, ? extends Long> map = gson.fromJson("{\"test\":123}", typeOfMap);
|
||||||
|
assertEquals(1, map.size());
|
||||||
|
assertEquals(new Long(123L), map.get("test"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private static class MyMap extends LinkedHashMap<String, String> {
|
private static class MyMap extends LinkedHashMap<String, String> {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user