提交 7fbc20e2 编写于 作者: J Juergen Hoeller

Undeprecate TypeVariableMap methods on GenericTypeResolver

Issue: SPR-15429
上级 42420a2d
......@@ -21,8 +21,12 @@ import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.springframework.util.Assert;
import org.springframework.util.ConcurrentReferenceHashMap;
/**
* Helper class for resolving generic types against type variables.
......@@ -38,6 +42,11 @@ import org.springframework.util.Assert;
*/
public abstract class GenericTypeResolver {
/** Cache from Class to TypeVariable Map */
@SuppressWarnings("rawtypes")
private static final Map<Class<?>, Map<TypeVariable, Type>> typeVariableCache = new ConcurrentReferenceHashMap<>();
/**
* Determine the target type for the given generic parameter type.
* @param methodParameter the method parameter specification
......@@ -196,4 +205,80 @@ public abstract class GenericTypeResolver {
return ResolvableType.NONE;
}
/**
* Resolve the specified generic type against the given TypeVariable map.
* <p>Used by Spring Data.
* @param genericType the generic type to resolve
* @param map the TypeVariable Map to resolved against
* @return the type if it resolves to a Class, or {@code Object.class} otherwise
*/
@SuppressWarnings("rawtypes")
public static Class<?> resolveType(Type genericType, Map<TypeVariable, Type> map) {
return ResolvableType.forType(genericType, new TypeVariableMapVariableResolver(map)).resolve(Object.class);
}
/**
* Build a mapping of {@link TypeVariable#getName TypeVariable names} to
* {@link Class concrete classes} for the specified {@link Class}.
* Searches all super types, enclosing types and interfaces.
* @see #resolveType(Type, Map)
*/
@SuppressWarnings("rawtypes")
public static Map<TypeVariable, Type> getTypeVariableMap(Class<?> clazz) {
Map<TypeVariable, Type> typeVariableMap = typeVariableCache.get(clazz);
if (typeVariableMap == null) {
typeVariableMap = new HashMap<>();
buildTypeVariableMap(ResolvableType.forClass(clazz), typeVariableMap);
typeVariableCache.put(clazz, Collections.unmodifiableMap(typeVariableMap));
}
return typeVariableMap;
}
@SuppressWarnings("rawtypes")
private static void buildTypeVariableMap(ResolvableType type, Map<TypeVariable, Type> typeVariableMap) {
if (type != ResolvableType.NONE) {
if (type.getType() instanceof ParameterizedType) {
TypeVariable<?>[] variables = type.resolve().getTypeParameters();
for (int i = 0; i < variables.length; i++) {
ResolvableType generic = type.getGeneric(i);
while (generic.getType() instanceof TypeVariable<?>) {
generic = generic.resolveType();
}
if (generic != ResolvableType.NONE) {
typeVariableMap.put(variables[i], generic.getType());
}
}
}
buildTypeVariableMap(type.getSuperType(), typeVariableMap);
for (ResolvableType interfaceType : type.getInterfaces()) {
buildTypeVariableMap(interfaceType, typeVariableMap);
}
if (type.resolve().isMemberClass()) {
buildTypeVariableMap(ResolvableType.forClass(type.resolve().getEnclosingClass()), typeVariableMap);
}
}
}
@SuppressWarnings({"serial", "rawtypes"})
private static class TypeVariableMapVariableResolver implements ResolvableType.VariableResolver {
private final Map<TypeVariable, Type> typeVariableMap;
public TypeVariableMapVariableResolver(Map<TypeVariable, Type> typeVariableMap) {
this.typeVariableMap = typeVariableMap;
}
@Override
public ResolvableType resolveVariable(TypeVariable<?> variable) {
Type type = this.typeVariableMap.get(variable);
return (type != null ? ResolvableType.forType(type) : null);
}
@Override
public Object getSource() {
return this.typeVariableMap;
}
}
}
......@@ -17,7 +17,11 @@
package org.springframework.core;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
......@@ -32,7 +36,7 @@ import static org.springframework.util.ReflectionUtils.*;
* @author Juergen Hoeller
* @author Sam Brannen
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
@SuppressWarnings({"unchecked", "rawtypes"})
public class GenericTypeResolverTests {
@Test
......@@ -72,11 +76,69 @@ public class GenericTypeResolverTests {
resolveReturnTypeArgument(findMethod(MyTypeWithMethods.class, "object"), MyInterfaceType.class));
}
@Test
public void testResolveType() {
Method intMessageMethod = findMethod(MyTypeWithMethods.class, "readIntegerInputMessage", MyInterfaceType.class);
MethodParameter intMessageMethodParam = new MethodParameter(intMessageMethod, 0);
assertEquals(MyInterfaceType.class,
resolveType(intMessageMethodParam.getGenericParameterType(), new HashMap<>()));
Method intArrMessageMethod = findMethod(MyTypeWithMethods.class, "readIntegerArrayInputMessage",
MyInterfaceType[].class);
MethodParameter intArrMessageMethodParam = new MethodParameter(intArrMessageMethod, 0);
assertEquals(MyInterfaceType[].class,
resolveType(intArrMessageMethodParam.getGenericParameterType(), new HashMap<>()));
Method genericArrMessageMethod = findMethod(MySimpleTypeWithMethods.class, "readGenericArrayInputMessage",
Object[].class);
MethodParameter genericArrMessageMethodParam = new MethodParameter(genericArrMessageMethod, 0);
Map<TypeVariable, Type> varMap = getTypeVariableMap(MySimpleTypeWithMethods.class);
assertEquals(Integer[].class, resolveType(genericArrMessageMethodParam.getGenericParameterType(), varMap));
}
@Test
public void testBoundParameterizedType() {
assertEquals(B.class, resolveTypeArgument(TestImpl.class, TestIfc.class));
}
@Test
public void testGetTypeVariableMap() throws Exception {
Map<TypeVariable, Type> map;
map = GenericTypeResolver.getTypeVariableMap(MySimpleInterfaceType.class);
assertThat(map.toString(), equalTo("{T=class java.lang.String}"));
map = GenericTypeResolver.getTypeVariableMap(MyCollectionInterfaceType.class);
assertThat(map.toString(), equalTo("{T=java.util.Collection<java.lang.String>}"));
map = GenericTypeResolver.getTypeVariableMap(MyCollectionSuperclassType.class);
assertThat(map.toString(), equalTo("{T=java.util.Collection<java.lang.String>}"));
map = GenericTypeResolver.getTypeVariableMap(MySimpleTypeWithMethods.class);
assertThat(map.toString(), equalTo("{T=class java.lang.Integer}"));
map = GenericTypeResolver.getTypeVariableMap(TopLevelClass.class);
assertThat(map.toString(), equalTo("{}"));
map = GenericTypeResolver.getTypeVariableMap(TypedTopLevelClass.class);
assertThat(map.toString(), equalTo("{T=class java.lang.Integer}"));
map = GenericTypeResolver.getTypeVariableMap(TypedTopLevelClass.TypedNested.class);
assertThat(map.size(), equalTo(2));
Type t = null;
Type x = null;
for (Map.Entry<TypeVariable, Type> entry : map.entrySet()) {
if (entry.getKey().toString().equals("T")) {
t = entry.getValue();
}
else {
x = entry.getValue();
}
}
assertThat(t, equalTo((Type) Integer.class));
assertThat(x, equalTo((Type) Long.class));
}
@Test
public void getGenericsCannotBeResolved() throws Exception {
// SPR-11030
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册