diff --git a/gson/GSON 2.0 NOTES.txt b/gson/GSON 2.0 NOTES.txt index e26aba83..45dbc71c 100644 --- a/gson/GSON 2.0 NOTES.txt +++ b/gson/GSON 2.0 NOTES.txt @@ -11,6 +11,7 @@ com.google.gson.functional.PrimitiveTest.testPrimitiveDoubleAutoboxedInASingleEl com.google.gson.functional.PrimitiveTest.testBigDecimalInASingleElementArrayDeserialization com.google.gson.functional.PrimitiveTest.testBigIntegerInASingleElementArrayDeserialization com.google.gson.functional.StringTest.testStringValueAsSingleElementArrayDeserialization +com.google.gson.functional.EnumTest.testTopLevelEnumInASingleElementArrayDeserialization GSON 1.x permitted primitive types to be overridden GSON 2.x doesn't. diff --git a/gson/src/main/java/com/google/gson/DefaultTypeAdapters.java b/gson/src/main/java/com/google/gson/DefaultTypeAdapters.java index 299cb6e7..91851106 100644 --- a/gson/src/main/java/com/google/gson/DefaultTypeAdapters.java +++ b/gson/src/main/java/com/google/gson/DefaultTypeAdapters.java @@ -47,9 +47,6 @@ final class DefaultTypeAdapters { private static final DefaultTimestampDeserializer TIMESTAMP_DESERIALIZER = new DefaultTimestampDeserializer(); - @SuppressWarnings("unchecked") - private static final EnumTypeAdapter ENUM_TYPE_ADAPTER = new EnumTypeAdapter(); - private static final CharacterTypeAdapter CHARACTER_TYPE_ADAPTER = new CharacterTypeAdapter(); private static final NumberTypeAdapter NUMBER_TYPE_ADAPTER = new NumberTypeAdapter(); @@ -59,15 +56,11 @@ final class DefaultTypeAdapters { // The constants DEFAULT_SERIALIZERS, DEFAULT_DESERIALIZERS, and DEFAULT_INSTANCE_CREATORS // must be defined after the constants for the type adapters. Otherwise, the type adapter // constants will appear as nulls. - private static final ParameterizedTypeHandlerMap> DEFAULT_SERIALIZERS = + static final ParameterizedTypeHandlerMap> DEFAULT_SERIALIZERS = createDefaultSerializers(); - static final ParameterizedTypeHandlerMap> DEFAULT_HIERARCHY_SERIALIZERS = - createDefaultHierarchySerializers(); - private static final ParameterizedTypeHandlerMap> DEFAULT_DESERIALIZERS = + static final ParameterizedTypeHandlerMap> DEFAULT_DESERIALIZERS = createDefaultDeserializers(); - static final ParameterizedTypeHandlerMap> DEFAULT_HIERARCHY_DESERIALIZERS = - createDefaultHierarchyDeserializers(); - private static final ParameterizedTypeHandlerMap> DEFAULT_INSTANCE_CREATORS = + static final ParameterizedTypeHandlerMap> DEFAULT_INSTANCE_CREATORS = createDefaultInstanceCreators(); private static ParameterizedTypeHandlerMap> createDefaultSerializers() { @@ -89,14 +82,6 @@ final class DefaultTypeAdapters { return map; } - private static ParameterizedTypeHandlerMap> createDefaultHierarchySerializers() { - ParameterizedTypeHandlerMap> map = - new ParameterizedTypeHandlerMap>(); - map.registerForTypeHierarchy(Enum.class, ENUM_TYPE_ADAPTER, true); - map.makeUnmodifiable(); - return map; - } - private static ParameterizedTypeHandlerMap> createDefaultDeserializers() { ParameterizedTypeHandlerMap> map = new ParameterizedTypeHandlerMap>(); @@ -115,14 +100,6 @@ final class DefaultTypeAdapters { return map; } - private static ParameterizedTypeHandlerMap> createDefaultHierarchyDeserializers() { - ParameterizedTypeHandlerMap> map = - new ParameterizedTypeHandlerMap>(); - map.registerForTypeHierarchy(Enum.class, wrapDeserializer(ENUM_TYPE_ADAPTER), true); - map.makeUnmodifiable(); - return map; - } - private static ParameterizedTypeHandlerMap> createDefaultInstanceCreators() { ParameterizedTypeHandlerMap> map = new ParameterizedTypeHandlerMap>(); @@ -135,32 +112,6 @@ final class DefaultTypeAdapters { return new JsonDeserializerExceptionWrapper(deserializer); } - static ParameterizedTypeHandlerMap> getDefaultSerializers() { - return DEFAULT_SERIALIZERS.copyOf(); - } - - static ParameterizedTypeHandlerMap> getAllDefaultSerializers() { - ParameterizedTypeHandlerMap> defaultSerializers = - DEFAULT_SERIALIZERS.copyOf(); - defaultSerializers.register(DEFAULT_HIERARCHY_SERIALIZERS); - return defaultSerializers; - } - - static ParameterizedTypeHandlerMap> getAllDefaultDeserializers() { - ParameterizedTypeHandlerMap> defaultDeserializers = - getDefaultDeserializers().copyOf(); - defaultDeserializers.register(DEFAULT_HIERARCHY_DESERIALIZERS); - return defaultDeserializers; - } - - static ParameterizedTypeHandlerMap> getDefaultDeserializers() { - return DEFAULT_DESERIALIZERS; - } - - static ParameterizedTypeHandlerMap> getDefaultInstanceCreators() { - return DEFAULT_INSTANCE_CREATORS; - } - /** * This type adapter supports three subclasses of date: Date, Timestamp, and * java.sql.Date. @@ -354,25 +305,6 @@ final class DefaultTypeAdapters { } } - @SuppressWarnings("unchecked") - private static final class EnumTypeAdapter> - implements JsonSerializer, JsonDeserializer { - public JsonElement serialize(T src, Type typeOfSrc, JsonSerializationContext context) { - return new JsonPrimitive(src.name()); - } - - @SuppressWarnings("cast") - public T deserialize(JsonElement json, Type classOfT, JsonDeserializationContext context) - throws JsonParseException { - return (T) Enum.valueOf((Class) classOfT, json.getAsString()); - } - - @Override - public String toString() { - return EnumTypeAdapter.class.getSimpleName(); - } - } - private static final class NumberTypeAdapter implements JsonSerializer, JsonDeserializer { public JsonElement serialize(Number src, Type typeOfSrc, JsonSerializationContext context) { diff --git a/gson/src/main/java/com/google/gson/Gson.java b/gson/src/main/java/com/google/gson/Gson.java index ffabf73b..b0c5c85d 100644 --- a/gson/src/main/java/com/google/gson/Gson.java +++ b/gson/src/main/java/com/google/gson/Gson.java @@ -168,9 +168,9 @@ public final class Gson { */ public Gson() { this(DEFAULT_EXCLUSION_STRATEGY, DEFAULT_EXCLUSION_STRATEGY, DEFAULT_NAMING_POLICY, - DefaultTypeAdapters.getDefaultInstanceCreators(), - false, DefaultTypeAdapters.getAllDefaultSerializers(), - DefaultTypeAdapters.getAllDefaultDeserializers(), false, DEFAULT_JSON_NON_EXECUTABLE, true, + DefaultTypeAdapters.DEFAULT_INSTANCE_CREATORS, + false, DefaultTypeAdapters.DEFAULT_SERIALIZERS, + DefaultTypeAdapters.DEFAULT_DESERIALIZERS, false, DEFAULT_JSON_NON_EXECUTABLE, true, false, false, LongSerializationPolicy.DEFAULT); } @@ -254,6 +254,7 @@ public final class Gson { )) .factory(new MapTypeAdapterFactory(constructorConstructor, complexMapKeySerialization)) .factory(ArrayTypeAdapter.FACTORY) + .factory(TypeAdapters.ENUM_FACTORY) .factory(reflectiveTypeAdapterFactory); this.miniGson = builder.build(); diff --git a/gson/src/main/java/com/google/gson/GsonBuilder.java b/gson/src/main/java/com/google/gson/GsonBuilder.java index 113346c9..ddd3de46 100644 --- a/gson/src/main/java/com/google/gson/GsonBuilder.java +++ b/gson/src/main/java/com/google/gson/GsonBuilder.java @@ -669,21 +669,17 @@ public final class GsonBuilder { serializationStrategies.add(exposeAnnotationSerializationExclusionStrategy); } - ParameterizedTypeHandlerMap> customSerializers = - DefaultTypeAdapters.DEFAULT_HIERARCHY_SERIALIZERS.copyOf(); - customSerializers.register(serializers.copyOf()); - ParameterizedTypeHandlerMap> customDeserializers = - DefaultTypeAdapters.DEFAULT_HIERARCHY_DESERIALIZERS.copyOf(); - customDeserializers.register(deserializers.copyOf()); + ParameterizedTypeHandlerMap> customSerializers = serializers.copyOf(); + ParameterizedTypeHandlerMap> customDeserializers = deserializers.copyOf(); addTypeAdaptersForDate(datePattern, dateStyle, timeStyle, customSerializers, customDeserializers); - customSerializers.registerIfAbsent(DefaultTypeAdapters.getDefaultSerializers()); - customDeserializers.registerIfAbsent(DefaultTypeAdapters.getDefaultDeserializers()); + customSerializers.registerIfAbsent(DefaultTypeAdapters.DEFAULT_SERIALIZERS); + customDeserializers.registerIfAbsent(DefaultTypeAdapters.DEFAULT_DESERIALIZERS); ParameterizedTypeHandlerMap> customInstanceCreators = instanceCreators.copyOf(); - customInstanceCreators.registerIfAbsent(DefaultTypeAdapters.getDefaultInstanceCreators()); + customInstanceCreators.registerIfAbsent(DefaultTypeAdapters.DEFAULT_INSTANCE_CREATORS); customSerializers.makeUnmodifiable(); customDeserializers.makeUnmodifiable(); diff --git a/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java b/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java index 36418a1a..90c1f85f 100644 --- a/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java +++ b/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java @@ -401,8 +401,36 @@ public final class TypeAdapters { public static final TypeAdapter.Factory LOCALE_FACTORY = newFactory(Locale.class, LOCALE); - public static TypeAdapter.Factory newFactory( - final TypeToken type, final TypeAdapter typeAdapter) { + private static final class EnumTypeAdapter> extends TypeAdapter { + private final Class classOfT; + + public EnumTypeAdapter(Class classOfT) { + this.classOfT = classOfT; + } + public T read(JsonReader reader) throws IOException { + return (T) Enum.valueOf((Class) classOfT, reader.nextString()); + } + + public void write(JsonWriter writer, T src) throws IOException { + writer.value(src.name()); + } + }; + + public static final TypeAdapter.Factory ENUM_FACTORY = newEnumTypeHierarchyFactory(Enum.class); + + public static TypeAdapter.Factory newEnumTypeHierarchyFactory(final Class clazz) { + return new TypeAdapter.Factory() { + @SuppressWarnings("unchecked") + public TypeAdapter create(MiniGson context, TypeToken typeToken) { + Class rawType = typeToken.getRawType(); + return clazz.isAssignableFrom(rawType) + ? (TypeAdapter) new EnumTypeAdapter(rawType) : null; + } + }; + } + + public static TypeAdapter.Factory newFactory( + final TypeToken type, final TypeAdapter typeAdapter) { return new TypeAdapter.Factory() { @SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal public TypeAdapter create(MiniGson context, TypeToken typeToken) { @@ -411,8 +439,8 @@ public final class TypeAdapters { }; } - public static TypeAdapter.Factory newFactory( - final Class type, final TypeAdapter typeAdapter) { + public static TypeAdapter.Factory newFactory( + final Class type, final TypeAdapter typeAdapter) { return new TypeAdapter.Factory() { @SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal public TypeAdapter create(MiniGson context, TypeToken typeToken) { @@ -421,8 +449,8 @@ public final class TypeAdapters { }; } - public static TypeAdapter.Factory newFactory( - final Class unboxed, final Class boxed, final TypeAdapter typeAdapter) { + public static TypeAdapter.Factory newFactory( + final Class unboxed, final Class boxed, final TypeAdapter typeAdapter) { return new TypeAdapter.Factory() { @SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal public TypeAdapter create(MiniGson context, TypeToken typeToken) { @@ -432,9 +460,10 @@ public final class TypeAdapters { }; } - public static TypeAdapter.Factory newTypeHierarchyFactory( - final Class clazz, final TypeAdapter typeAdapter) { + public static TypeAdapter.Factory newTypeHierarchyFactory( + final Class clazz, final TypeAdapter typeAdapter) { return new TypeAdapter.Factory() { + @SuppressWarnings("unchecked") public TypeAdapter create(MiniGson context, TypeToken typeToken) { return clazz.isAssignableFrom(typeToken.getRawType()) ? (TypeAdapter) typeAdapter : null; } diff --git a/gson/src/test/java/com/google/gson/FunctionWithInternalDependenciesTest.java b/gson/src/test/java/com/google/gson/FunctionWithInternalDependenciesTest.java index 144bb7d6..88a810fa 100644 --- a/gson/src/test/java/com/google/gson/FunctionWithInternalDependenciesTest.java +++ b/gson/src/test/java/com/google/gson/FunctionWithInternalDependenciesTest.java @@ -37,9 +37,9 @@ public class FunctionWithInternalDependenciesTest extends TestCase { strategies.add(new ModifierBasedExclusionStrategy(Modifier.TRANSIENT, Modifier.STATIC)); ExclusionStrategy exclusionStrategy = new DisjunctionExclusionStrategy(strategies); Gson gson = new Gson(exclusionStrategy, exclusionStrategy, Gson.DEFAULT_NAMING_POLICY, - DefaultTypeAdapters.getDefaultInstanceCreators(), - false, DefaultTypeAdapters.getDefaultSerializers(), - DefaultTypeAdapters.getDefaultDeserializers(), false, Gson.DEFAULT_JSON_NON_EXECUTABLE, + DefaultTypeAdapters.DEFAULT_INSTANCE_CREATORS, + false, DefaultTypeAdapters.DEFAULT_SERIALIZERS, + DefaultTypeAdapters.DEFAULT_DESERIALIZERS, false, Gson.DEFAULT_JSON_NON_EXECUTABLE, true, false, false, LongSerializationPolicy.DEFAULT); assertEquals("{}", gson.toJson(new ClassWithNoFields() { // empty anonymous class diff --git a/gson/src/test/java/com/google/gson/functional/EnumTest.java b/gson/src/test/java/com/google/gson/functional/EnumTest.java index bdb2cc34..e5c2df50 100644 --- a/gson/src/test/java/com/google/gson/functional/EnumTest.java +++ b/gson/src/test/java/com/google/gson/functional/EnumTest.java @@ -62,12 +62,6 @@ public class EnumTest extends TestCase { assertEquals(MyEnum.VALUE1, result); } - public void testTopLevelEnumInASingleElementArrayDeserialization() { - String json = "[" + MyEnum.VALUE1.getExpectedJson() + "]"; - MyEnum target = gson.fromJson(json, MyEnum.class); - assertEquals(json, "[" + target.getExpectedJson() + "]"); - } - public void testCollectionOfEnumsSerialization() { Type type = new TypeToken>() {}.getType(); Collection target = new ArrayList();