Add support for wildcard type on Maps, Collections and other parameterized types.
diff --git a/gson/src/main/java/com/google/gson/ParameterizedTypeHandlerMap.java b/gson/src/main/java/com/google/gson/ParameterizedTypeHandlerMap.java
index 685ee83..8378ce9 100644
--- a/gson/src/main/java/com/google/gson/ParameterizedTypeHandlerMap.java
+++ b/gson/src/main/java/com/google/gson/ParameterizedTypeHandlerMap.java
@@ -70,6 +70,7 @@
       rawType = ((ParameterizedType)type).getRawType();
       handler = map.get(rawType);
     }
+
     // Check for map or collection 
     if (handler == null) {
       if (rawType instanceof Class) {
@@ -87,13 +88,20 @@
   }
   
   private synchronized T getRawHandlerFor(Type type) {
-    T handler = map.get(type);
     if (type instanceof Map) {
-      handler = map.get(Map.class);
+      return map.get(Map.class);
     } 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) {
diff --git a/gson/src/main/java/com/google/gson/TypeUtils.java b/gson/src/main/java/com/google/gson/TypeUtils.java
index 50696bd..acda71a 100644
--- a/gson/src/main/java/com/google/gson/TypeUtils.java
+++ b/gson/src/main/java/com/google/gson/TypeUtils.java
@@ -20,6 +20,7 @@
 import java.lang.reflect.GenericArrayType;
 import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
+import java.lang.reflect.WildcardType;
 
 /**
  * Utility class containing some methods for obtaining information on types.
@@ -75,6 +76,9 @@
       GenericArrayType actualType = (GenericArrayType) type;
       Class<?> rawClass = toRawClass(actualType.getGenericComponentType());
       return wrapWithArray(rawClass);
+    } else if (type instanceof WildcardType) {
+      WildcardType castedType = (WildcardType) type;
+      return toRawClass(castedType.getUpperBounds()[0]);
     } else {
       throw new IllegalArgumentException("Type \'" + type + "\' is not a Class, "
           + "ParameterizedType, or GenericArrayType. Can't extract class.");
diff --git a/gson/src/test/java/com/google/gson/functional/CollectionTest.java b/gson/src/test/java/com/google/gson/functional/CollectionTest.java
index 05ee8cc..d397b55 100644
--- a/gson/src/test/java/com/google/gson/functional/CollectionTest.java
+++ b/gson/src/test/java/com/google/gson/functional/CollectionTest.java
@@ -29,6 +29,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
@@ -244,6 +245,44 @@
     } catch (JsonParseException expected) {
     }
   }
+  
+  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")
   private static int[] toIntArray(Collection collection) {
@@ -259,4 +298,21 @@
     }
     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;
+    }
+  }
 }
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 9d7bb0a..ea2501c 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,7 @@
 package com.google.gson.functional;
 
 import java.lang.reflect.Type;
+import java.util.Collection;
 import java.util.LinkedHashMap;
 import java.util.Map;
 
@@ -162,7 +163,7 @@
   }
   
   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) {
         return new MyMap();
       }      
@@ -173,6 +174,25 @@
     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 final long serialVersionUID = 1L;