From 64dc53ffc40ac80925be50523e3c2cea6ad97da9 Mon Sep 17 00:00:00 2001 From: Inderjeet Singh Date: Thu, 4 Aug 2011 23:55:52 +0000 Subject: [PATCH] Added support for runtime type determination while serializing collections and its subclasses. This currently doesn't work since Gson register a hierarchy type adapter for Collections that takes precedence over this. --- .../internal/bind/CollectionTypeAdapter.java | 17 ++++---- .../com/google/gson/common/TestTypes.java | 13 +++++- .../gson/functional/InheritanceTest.java | 40 +++++++++++++------ 3 files changed, 48 insertions(+), 22 deletions(-) diff --git a/gson/src/main/java/com/google/gson/internal/bind/CollectionTypeAdapter.java b/gson/src/main/java/com/google/gson/internal/bind/CollectionTypeAdapter.java index 9369fbfa..33e96be7 100644 --- a/gson/src/main/java/com/google/gson/internal/bind/CollectionTypeAdapter.java +++ b/gson/src/main/java/com/google/gson/internal/bind/CollectionTypeAdapter.java @@ -18,7 +18,6 @@ package com.google.gson.internal.bind; import java.io.IOException; import java.lang.reflect.Constructor; -import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Collection; @@ -39,9 +38,6 @@ public final class CollectionTypeAdapter extends TypeAdapter> { public static final Factory FACTORY = new Factory() { public TypeAdapter create(MiniGson context, TypeToken typeToken) { Type type = typeToken.getType(); - if (!(type instanceof ParameterizedType)) { - return null; - } Class rawType = typeToken.getRawType(); if (!Collection.class.isAssignableFrom(rawType)) { @@ -69,16 +65,20 @@ public final class CollectionTypeAdapter extends TypeAdapter> { } @SuppressWarnings("unchecked") // create() doesn't define a type parameter - TypeAdapter result = new CollectionTypeAdapter(elementTypeAdapter, constructor); + TypeAdapter result = new CollectionTypeAdapter(context, elementType, elementTypeAdapter, constructor); return result; } }; + private final MiniGson context; + private final Type elementType; private final TypeAdapter elementTypeAdapter; private final Constructor> constructor; - public CollectionTypeAdapter(TypeAdapter elementTypeAdapter, + public CollectionTypeAdapter(MiniGson context, Type elementType, TypeAdapter elementTypeAdapter, Constructor> constructor) { + this.context = context; + this.elementType = elementType; this.elementTypeAdapter = elementTypeAdapter; this.constructor = constructor; } @@ -107,7 +107,10 @@ public final class CollectionTypeAdapter extends TypeAdapter> { writer.beginArray(); for (E element : collection) { - elementTypeAdapter.write(writer, element); + Type runtimeType = Reflection.getRuntimeTypeIfMoreSpecific(elementType, collection, element); + TypeAdapter t = runtimeType != elementType ? + context.getAdapter(TypeToken.get(runtimeType)) : elementTypeAdapter; + t.write(writer, element); } writer.endArray(); } diff --git a/gson/src/test/java/com/google/gson/common/TestTypes.java b/gson/src/test/java/com/google/gson/common/TestTypes.java index f8e86696..4754d97b 100644 --- a/gson/src/test/java/com/google/gson/common/TestTypes.java +++ b/gson/src/test/java/com/google/gson/common/TestTypes.java @@ -16,6 +16,9 @@ package com.google.gson.common; +import java.lang.reflect.Type; +import java.util.Collection; + import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; @@ -26,8 +29,6 @@ import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; import com.google.gson.annotations.SerializedName; -import java.lang.reflect.Type; - /** * Types used for testing JSON serialization and deserialization * @@ -66,6 +67,14 @@ public class TestTypes { } } + public static class ClassWithBaseCollectionField { + public static final String FIELD_KEY = "base"; + public final Collection base; + public ClassWithBaseCollectionField(Collection base) { + this.base = base; + } + } + public static class BaseSerializer implements JsonSerializer { public static final String NAME = BaseSerializer.class.getSimpleName(); public JsonElement serialize(Base src, Type typeOfSrc, JsonSerializationContext context) { diff --git a/gson/src/test/java/com/google/gson/functional/InheritanceTest.java b/gson/src/test/java/com/google/gson/functional/InheritanceTest.java index 2940d1a2..d4389813 100644 --- a/gson/src/test/java/com/google/gson/functional/InheritanceTest.java +++ b/gson/src/test/java/com/google/gson/functional/InheritanceTest.java @@ -15,19 +15,7 @@ */ package com.google.gson.functional; -import com.google.gson.Gson; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.common.TestTypes.BagOfPrimitives; -import com.google.gson.common.TestTypes.Base; -import com.google.gson.common.TestTypes.ClassWithBaseArrayField; -import com.google.gson.common.TestTypes.ClassWithBaseField; -import com.google.gson.common.TestTypes.Nested; -import com.google.gson.common.TestTypes.Sub; - -import junit.framework.TestCase; - +import java.util.ArrayList; import java.util.Collection; import java.util.LinkedList; import java.util.List; @@ -36,6 +24,20 @@ import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; +import junit.framework.TestCase; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.common.TestTypes.BagOfPrimitives; +import com.google.gson.common.TestTypes.Base; +import com.google.gson.common.TestTypes.ClassWithBaseArrayField; +import com.google.gson.common.TestTypes.ClassWithBaseCollectionField; +import com.google.gson.common.TestTypes.ClassWithBaseField; +import com.google.gson.common.TestTypes.Nested; +import com.google.gson.common.TestTypes.Sub; + /** * Functional tests for Json serialization and deserialization of classes with * inheritance hierarchies. @@ -84,6 +86,18 @@ public class InheritanceTest extends TestCase { } } + public void testClassWithBaseCollectionFieldSerialization() { + Collection baseClasses = new ArrayList(); + baseClasses.add(new Sub()); + baseClasses.add(new Sub()); + ClassWithBaseCollectionField sub = new ClassWithBaseCollectionField(baseClasses); + JsonObject json = gson.toJsonTree(sub).getAsJsonObject(); + JsonArray bases = json.get(ClassWithBaseArrayField.FIELD_KEY).getAsJsonArray(); + for (JsonElement element : bases) { + assertEquals(Sub.SUB_NAME, element.getAsJsonObject().get(Sub.SUB_FIELD_KEY).getAsString()); + } + } + public void testBaseSerializedAsSub() { Base base = new Sub(); JsonObject json = gson.toJsonTree(base).getAsJsonObject();