From a38b757bc4fddfd57ab762fbf192dd2b3fc6be22 Mon Sep 17 00:00:00 2001 From: Marcono1234 Date: Tue, 25 Jul 2023 22:00:26 +0200 Subject: [PATCH] Support non-generic type for `TypeToken.getParameterized` for legacy reasons (#2447) This partially restores the behavior before a589ef20087b4b0f1ec3048d3ceaef1eedccd09d, except that back then for a non-generic type a bogus `TypeToken(ParameterizedType)` was created, whereas now a `TypeToken(Class)` is created instead. --- .../com/google/gson/reflect/TypeToken.java | 28 ++++++++++--------- .../google/gson/reflect/TypeTokenTest.java | 5 +++- 2 files changed, 19 insertions(+), 14 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 4a695666..3921a70b 100644 --- a/gson/src/main/java/com/google/gson/reflect/TypeToken.java +++ b/gson/src/main/java/com/google/gson/reflect/TypeToken.java @@ -337,9 +337,12 @@ public class TypeToken { * As seen here the result is a {@code TypeToken}; this method cannot provide any type safety, * and care must be taken to pass in the correct number of type arguments. * + *

If {@code rawType} is a non-generic class and no type arguments are provided, this method + * simply delegates to {@link #get(Class)} and creates a {@code TypeToken(Class)}. + * * @throws IllegalArgumentException - * If {@code rawType} is not of type {@code Class}, if it is not a generic type, or if the - * type arguments are invalid for the raw type + * If {@code rawType} is not of type {@code Class}, or if the type arguments are invalid for + * the raw type */ public static TypeToken getParameterized(Type rawType, Type... typeArguments) { Objects.requireNonNull(rawType); @@ -354,10 +357,16 @@ public class TypeToken { Class rawClass = (Class) rawType; TypeVariable[] typeVariables = rawClass.getTypeParameters(); - // Note: Does not check if owner type of rawType is generic because this factory method - // does not support specifying owner type - if (typeVariables.length == 0) { - throw new IllegalArgumentException(rawClass.getName() + " is not a generic type"); + int expectedArgsCount = typeVariables.length; + int actualArgsCount = typeArguments.length; + if (actualArgsCount != expectedArgsCount) { + throw new IllegalArgumentException(rawClass.getName() + " requires " + expectedArgsCount + + " type arguments, but got " + actualArgsCount); + } + + // For legacy reasons create a TypeToken(Class) if the type is not generic + if (typeArguments.length == 0) { + return get(rawClass); } // Check for this here to avoid misleading exception thrown by ParameterizedTypeImpl @@ -366,13 +375,6 @@ public class TypeToken { + " it requires specifying an owner type"); } - int expectedArgsCount = typeVariables.length; - int actualArgsCount = typeArguments.length; - if (actualArgsCount != expectedArgsCount) { - throw new IllegalArgumentException(rawClass.getName() + " requires " + expectedArgsCount + - " type arguments, but got " + actualArgsCount); - } - for (int i = 0; i < expectedArgsCount; i++) { Type typeArgument = Objects.requireNonNull(typeArguments[i], "Type argument must not be null"); Class rawTypeArgument = $Gson$Types.getRawType(typeArgument); 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 d38f05b1..4c1ccf0d 100644 --- a/gson/src/test/java/com/google/gson/reflect/TypeTokenTest.java +++ b/gson/src/test/java/com/google/gson/reflect/TypeTokenTest.java @@ -146,6 +146,9 @@ public final class TypeTokenTest { class LocalGenericClass {} TypeToken expectedLocalType = new TypeToken>() {}; assertThat(TypeToken.getParameterized(LocalGenericClass.class, Integer.class)).isEqualTo(expectedLocalType); + + // For legacy reasons, if requesting parameterized type for non-generic class, create a `TypeToken(Class)` + assertThat(TypeToken.getParameterized(String.class)).isEqualTo(TypeToken.get(String.class)); } @Test @@ -158,7 +161,7 @@ public final class TypeTokenTest { assertThat(e).hasMessageThat().isEqualTo("rawType must be of type Class, but was java.lang.String[]"); e = assertThrows(IllegalArgumentException.class, () -> TypeToken.getParameterized(String.class, Number.class)); - assertThat(e).hasMessageThat().isEqualTo("java.lang.String is not a generic type"); + assertThat(e).hasMessageThat().isEqualTo("java.lang.String requires 0 type arguments, but got 1"); e = assertThrows(IllegalArgumentException.class, () -> TypeToken.getParameterized(List.class, new Type[0])); assertThat(e).hasMessageThat().isEqualTo("java.util.List requires 1 type arguments, but got 0");