Undeprecate TypeVariableMap methods on GenericTypeResolver

Issue: SPR-15429
This commit is contained in:
Juergen Hoeller
2017-04-11 10:09:09 +02:00
parent 42420a2df7
commit 7fbc20e225
2 changed files with 148 additions and 1 deletions

View File

@@ -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;
}
}
}