Support non-generic type for TypeToken.getParameterized
for legacy reasons (#2447)
This partially restores the behavior before a589ef2008
,
except that back then for a non-generic type a bogus `TypeToken(ParameterizedType)`
was created, whereas now a `TypeToken(Class)` is created instead.
This commit is contained in:
parent
79ae239a49
commit
a38b757bc4
@ -337,9 +337,12 @@ public class TypeToken<T> {
|
|||||||
* As seen here the result is a {@code TypeToken<?>}; this method cannot provide any type safety,
|
* 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.
|
* 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
|
* @throws IllegalArgumentException
|
||||||
* If {@code rawType} is not of type {@code Class}, if it is not a generic type, or if the
|
* If {@code rawType} is not of type {@code Class}, or if the type arguments are invalid for
|
||||||
* type arguments are invalid for the raw type
|
* the raw type
|
||||||
*/
|
*/
|
||||||
public static TypeToken<?> getParameterized(Type rawType, Type... typeArguments) {
|
public static TypeToken<?> getParameterized(Type rawType, Type... typeArguments) {
|
||||||
Objects.requireNonNull(rawType);
|
Objects.requireNonNull(rawType);
|
||||||
@ -354,10 +357,16 @@ public class TypeToken<T> {
|
|||||||
Class<?> rawClass = (Class<?>) rawType;
|
Class<?> rawClass = (Class<?>) rawType;
|
||||||
TypeVariable<?>[] typeVariables = rawClass.getTypeParameters();
|
TypeVariable<?>[] typeVariables = rawClass.getTypeParameters();
|
||||||
|
|
||||||
// Note: Does not check if owner type of rawType is generic because this factory method
|
int expectedArgsCount = typeVariables.length;
|
||||||
// does not support specifying owner type
|
int actualArgsCount = typeArguments.length;
|
||||||
if (typeVariables.length == 0) {
|
if (actualArgsCount != expectedArgsCount) {
|
||||||
throw new IllegalArgumentException(rawClass.getName() + " is not a generic type");
|
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
|
// Check for this here to avoid misleading exception thrown by ParameterizedTypeImpl
|
||||||
@ -366,13 +375,6 @@ public class TypeToken<T> {
|
|||||||
+ " it requires specifying an owner type");
|
+ " 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++) {
|
for (int i = 0; i < expectedArgsCount; i++) {
|
||||||
Type typeArgument = Objects.requireNonNull(typeArguments[i], "Type argument must not be null");
|
Type typeArgument = Objects.requireNonNull(typeArguments[i], "Type argument must not be null");
|
||||||
Class<?> rawTypeArgument = $Gson$Types.getRawType(typeArgument);
|
Class<?> rawTypeArgument = $Gson$Types.getRawType(typeArgument);
|
||||||
|
@ -146,6 +146,9 @@ public final class TypeTokenTest {
|
|||||||
class LocalGenericClass<T> {}
|
class LocalGenericClass<T> {}
|
||||||
TypeToken<?> expectedLocalType = new TypeToken<LocalGenericClass<Integer>>() {};
|
TypeToken<?> expectedLocalType = new TypeToken<LocalGenericClass<Integer>>() {};
|
||||||
assertThat(TypeToken.getParameterized(LocalGenericClass.class, Integer.class)).isEqualTo(expectedLocalType);
|
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
|
@Test
|
||||||
@ -158,7 +161,7 @@ public final class TypeTokenTest {
|
|||||||
assertThat(e).hasMessageThat().isEqualTo("rawType must be of type Class, but was java.lang.String[]");
|
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));
|
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]));
|
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");
|
assertThat(e).hasMessageThat().isEqualTo("java.util.List requires 1 type arguments, but got 0");
|
||||||
|
Loading…
Reference in New Issue
Block a user