From cba030776434f79f03b84de5a7e7bd50461927cb Mon Sep 17 00:00:00 2001 From: Marcono1234 Date: Wed, 16 Feb 2022 00:58:27 +0100 Subject: [PATCH] Remove TypeToken check for type variable As mentioned in review comments, there are cases during serialization where usage of the type variable is not so problematic (but still not ideal). --- .../com/google/gson/reflect/TypeToken.java | 40 +++---------- .../google/gson/reflect/TypeTokenTest.java | 56 ------------------- 2 files changed, 7 insertions(+), 89 deletions(-) diff --git a/gson/src/main/java/com/google/gson/reflect/TypeToken.java b/gson/src/main/java/com/google/gson/reflect/TypeToken.java index f8e75a18ac..dea636da88 100644 --- a/gson/src/main/java/com/google/gson/reflect/TypeToken.java +++ b/gson/src/main/java/com/google/gson/reflect/TypeToken.java @@ -22,7 +22,6 @@ import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; -import java.lang.reflect.WildcardType; import java.util.HashMap; import java.util.Map; @@ -38,6 +37,12 @@ *

* {@code TypeToken> list = new TypeToken>() {};} * + *

Capturing a type variable as type argument of a {@code TypeToken} should + * be avoided. Due to type erasure the runtime type of a type variable is not + * available to Gson and therefore it cannot provide the functionality one + * might expect, which gives a false sense of type-safety at compilation time + * and can lead to an unexpected {@code ClassCastException} at runtime. + * * @author Bob Lee * @author Sven Mawson * @author Jesse Wilson @@ -54,13 +59,6 @@ public class TypeToken { *

Clients create an empty anonymous subclass. Doing so embeds the type * parameter in the anonymous class's type hierarchy so we can reconstitute it * at runtime despite erasure. - * - *

Because {@code TypeToken} is mainly intended for usage with Gson - * (and not other libraries) using a type variable as part of the type - * argument for {@code TypeToken} is not allowed. Due to type erasure the - * runtime type of a type variable is not available to Gson and therefore - * it cannot provide the functionality the user might expect, which would - * give a false sense of type-safety. */ @SuppressWarnings("unchecked") protected TypeToken() { @@ -89,9 +87,7 @@ private Type getTypeTokenTypeArgument() { if (superclass instanceof ParameterizedType) { ParameterizedType parameterized = (ParameterizedType) superclass; if (parameterized.getRawType() == TypeToken.class) { - Type typeArgument = $Gson$Types.canonicalize(parameterized.getActualTypeArguments()[0]); - verifyNoTypeVariable(typeArgument); - return typeArgument; + return $Gson$Types.canonicalize(parameterized.getActualTypeArguments()[0]); } } // Check for raw TypeToken as superclass @@ -104,28 +100,6 @@ else if (superclass == TypeToken.class) { throw new IllegalStateException("Must only create direct subclasses of TypeToken"); } - private static void verifyNoTypeVariable(Type type) { - if (type instanceof TypeVariable) { - TypeVariable typeVariable = (TypeVariable) type; - throw new IllegalArgumentException("TypeToken type argument must not contain a type variable; captured type variable " - + typeVariable.getName() + " declared by " + typeVariable.getGenericDeclaration()); - } else if (type instanceof GenericArrayType) { - verifyNoTypeVariable(((GenericArrayType) type).getGenericComponentType()); - } else if (type instanceof ParameterizedType) { - for (Type typeArgument : ((ParameterizedType) type).getActualTypeArguments()) { - verifyNoTypeVariable(typeArgument); - } - } else if (type instanceof WildcardType) { - WildcardType wildcardType = (WildcardType) type; - for (Type bound : wildcardType.getLowerBounds()) { - verifyNoTypeVariable(bound); - } - for (Type bound : wildcardType.getUpperBounds()) { - verifyNoTypeVariable(bound); - } - } - } - /** * Returns the raw (non-generic) type for this type. */ diff --git a/gson/src/test/java/com/google/gson/reflect/TypeTokenTest.java b/gson/src/test/java/com/google/gson/reflect/TypeTokenTest.java index 0d82d283bb..1cdd7361af 100644 --- a/gson/src/test/java/com/google/gson/reflect/TypeTokenTest.java +++ b/gson/src/test/java/com/google/gson/reflect/TypeTokenTest.java @@ -146,62 +146,6 @@ class SubSubTypeToken2 extends SubTypeToken {} } } - /** - * TypeToken type argument must not contain a type variable because, due to - * type erasure, at runtime only the bound of the type variable is available - * which is likely not what the user wanted. - * - *

Note that type variables are allowed for the methods calling {@code TypeToken(Type)} - * because there the return type is {@code TypeToken} which does not give - * a false sense of type-safety. - */ - public void testTypeTokenTypeVariable() { - try { - new TypeToken() {}; - fail(); - } catch (IllegalArgumentException expected) { - assertEquals("TypeToken type argument must not contain a type variable; captured type variable T " - + "declared by public void com.google.gson.reflect.TypeTokenTest.testTypeTokenTypeVariable()", - expected.getMessage()); - } - - try { - new TypeToken>>() {}; - fail(); - } catch (IllegalArgumentException expected) { - assertEquals("TypeToken type argument must not contain a type variable; captured type variable T " - + "declared by public void com.google.gson.reflect.TypeTokenTest.testTypeTokenTypeVariable()", - expected.getMessage()); - } - - try { - new TypeToken>>() {}; - fail(); - } catch (IllegalArgumentException expected) { - assertEquals("TypeToken type argument must not contain a type variable; captured type variable T " - + "declared by public void com.google.gson.reflect.TypeTokenTest.testTypeTokenTypeVariable()", - expected.getMessage()); - } - - try { - new TypeToken>>() {}; - fail(); - } catch (IllegalArgumentException expected) { - assertEquals("TypeToken type argument must not contain a type variable; captured type variable T " - + "declared by public void com.google.gson.reflect.TypeTokenTest.testTypeTokenTypeVariable()", - expected.getMessage()); - } - - try { - new TypeToken[]>() {}; - fail(); - } catch (IllegalArgumentException expected) { - assertEquals("TypeToken type argument must not contain a type variable; captured type variable T " - + "declared by public void com.google.gson.reflect.TypeTokenTest.testTypeTokenTypeVariable()", - expected.getMessage()); - } - } - @SuppressWarnings("rawtypes") public void testTypeTokenRaw() { try {