Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support non-generic type for TypeToken.getParameterized for legacy reasons #2447

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 15 additions & 13 deletions gson/src/main/java/com/google/gson/reflect/TypeToken.java
Original file line number Diff line number Diff line change
Expand Up @@ -337,9 +337,12 @@ public static <T> TypeToken<T> get(Class<T> type) {
* 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.
*
* <p>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);
Expand All @@ -354,10 +357,16 @@ public static TypeToken<?> getParameterized(Type rawType, Type... typeArguments)
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
Expand All @@ -366,13 +375,6 @@ public static TypeToken<?> getParameterized(Type rawType, Type... typeArguments)
+ " 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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,9 @@ public void testParameterizedFactory() {
class LocalGenericClass<T> {}
TypeToken<?> expectedLocalType = new TypeToken<LocalGenericClass<Integer>>() {};
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
Expand All @@ -158,7 +161,7 @@ public void testParameterizedFactory_Invalid() {
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");
Expand Down