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 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 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 > list = 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 {