Convenient forType methods for ParameterizedTypeReference

Issue: SPR-16054

(cherry picked from commit 53091c7)
This commit is contained in:
Juergen Hoeller 2017-10-09 13:59:01 +02:00
parent ab081c4fab
commit a4803d8b0f
4 changed files with 79 additions and 18 deletions

View File

@ -53,6 +53,10 @@ public abstract class ParameterizedTypeReference<T> {
this.type = parameterizedType.getActualTypeArguments()[0];
}
private ParameterizedTypeReference(Type type) {
this.type = type;
}
public Type getType() {
return this.type;
@ -75,6 +79,19 @@ public abstract class ParameterizedTypeReference<T> {
}
/**
* Build a {@code ParameterizedTypeReference} wrapping the given type.
* @param type a generic type (possibly obtained via reflection,
* e.g. from {@link java.lang.reflect.Method#getGenericReturnType()})
* @return a corresponding reference which may be passed into
* {@code ParameterizedTypeReference}-accepting methods
* @since 4.3.12
*/
public static <T> ParameterizedTypeReference<T> forType(Type type) {
return new ParameterizedTypeReference<T>(type) {
};
}
private static Class<?> findParameterizedTypeReferenceSubclass(Class<?> child) {
Class<?> parent = child.getSuperclass();
if (Object.class == parent) {

View File

@ -1309,6 +1309,19 @@ public class ResolvableType implements Serializable {
return forType(type, variableResolver);
}
/**
* Return a {@link ResolvableType} for the specified {@link ParameterizedTypeReference}.
* Note: The resulting {@link ResolvableType} may not be {@link Serializable}.
* @param typeReference the reference to obtain the source type from
* @return a {@link ResolvableType} for the specified {@link ParameterizedTypeReference}
* @since 4.3.12
* @see #forType(Type)
*/
public static ResolvableType forType(ParameterizedTypeReference<?> typeReference) {
return forType(typeReference.getType(), null, null);
}
/**
* Return a {@link ResolvableType} for the specified {@link Type} backed by a given
* {@link VariableResolver}.
@ -1545,7 +1558,7 @@ public class ResolvableType implements Serializable {
}
WildcardType wildcardType = (WildcardType) resolveToWildcard.type;
Kind boundsType = (wildcardType.getLowerBounds().length > 0 ? Kind.LOWER : Kind.UPPER);
Type[] bounds = boundsType == Kind.UPPER ? wildcardType.getUpperBounds() : wildcardType.getLowerBounds();
Type[] bounds = (boundsType == Kind.UPPER ? wildcardType.getUpperBounds() : wildcardType.getLowerBounds());
ResolvableType[] resolvableBounds = new ResolvableType[bounds.length];
for (int i = 0; i < bounds.length; i++) {
resolvableBounds[i] = ResolvableType.forType(bounds[i], type.variableResolver);

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -33,25 +33,40 @@ import static org.junit.Assert.*;
public class ParameterizedTypeReferenceTests {
@Test
public void map() throws NoSuchMethodException {
Type mapType = getClass().getMethod("mapMethod").getGenericReturnType();
ParameterizedTypeReference<Map<Object,String>> mapTypeReference = new ParameterizedTypeReference<Map<Object,String>>() {};
assertEquals(mapType, mapTypeReference.getType());
}
@Test
public void list() throws NoSuchMethodException {
Type mapType = getClass().getMethod("listMethod").getGenericReturnType();
ParameterizedTypeReference<List<String>> mapTypeReference = new ParameterizedTypeReference<List<String>>() {};
assertEquals(mapType, mapTypeReference.getType());
}
@Test
public void string() {
public void stringTypeReference() {
ParameterizedTypeReference<String> typeReference = new ParameterizedTypeReference<String>() {};
assertEquals(String.class, typeReference.getType());
}
@Test
public void mapTypeReference() throws Exception {
Type mapType = getClass().getMethod("mapMethod").getGenericReturnType();
ParameterizedTypeReference<Map<Object,String>> typeReference = new ParameterizedTypeReference<Map<Object,String>>() {};
assertEquals(mapType, typeReference.getType());
}
@Test
public void listTypeReference() throws Exception {
Type listType = getClass().getMethod("listMethod").getGenericReturnType();
ParameterizedTypeReference<List<String>> typeReference = new ParameterizedTypeReference<List<String>>() {};
assertEquals(listType, typeReference.getType());
}
@Test
public void reflectiveTypeReferenceWithSpecificDeclaration() throws Exception{
Type listType = getClass().getMethod("listMethod").getGenericReturnType();
ParameterizedTypeReference<List<String>> typeReference = ParameterizedTypeReference.forType(listType);
assertEquals(listType, typeReference.getType());
}
@Test
public void reflectiveTypeReferenceWithGenericDeclaration() throws Exception{
Type listType = getClass().getMethod("listMethod").getGenericReturnType();
ParameterizedTypeReference<?> typeReference = ParameterizedTypeReference.forType(listType);
assertEquals(listType, typeReference.getType());
}
public static Map<Object, String> mapMethod() {
return null;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -869,6 +869,22 @@ public class ResolvableTypeTests {
assertThat(this.typeVariableCaptor.getValue().getName(), equalTo("T"));
}
@Test
public void resolveTypeVariableFromReflectiveParameterizedTypeReference() throws Exception {
Type sourceType = Methods.class.getMethod("typedReturn").getGenericReturnType();
ResolvableType type = ResolvableType.forType(ParameterizedTypeReference.forType(sourceType));
assertThat(type.resolve(), nullValue());
assertThat(type.getType().toString(), equalTo("T"));
}
@Test
public void resolveTypeVariableFromDeclaredParameterizedTypeReference() throws Exception {
Type sourceType = Methods.class.getMethod("charSequenceReturn").getGenericReturnType();
ResolvableType reflectiveType = ResolvableType.forType(sourceType);
ResolvableType declaredType = ResolvableType.forType(new ParameterizedTypeReference<List<CharSequence>>() {});
assertEquals(reflectiveType, declaredType);
}
@Test
public void toStrings() throws Exception {
assertThat(ResolvableType.NONE.toString(), equalTo("?"));