DATACMNS-1196 - Fixed generics lookup for nested generics in ParameterizedTypeInformation.
We now eagerly resolve a generics declaration chain, which we previously - erroneously - expected GenericTypeResolver to do for us. Simplified TypeVariableTypeInformation implementation. Renamed ParameterizedTypeUnitTests to ParameterizedTypeInformationUnitTests.
This commit is contained in:
@@ -59,31 +59,6 @@ class ParameterizedTypeInformation<T> extends ParentTypeAwareTypeInformation<T>
|
||||
this.resolved = Lazy.of(() -> isResolvedCompletely());
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the type variables to be used. Uses the parent's type variable map but overwrites variables locally
|
||||
* declared.
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
* @param resolvedType must not be {@literal null}.
|
||||
* @param parent must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
private static Map<TypeVariable<?>, Type> calculateTypeVariables(ParameterizedType type, Class<?> resolvedType,
|
||||
TypeDiscoverer<?> parent) {
|
||||
|
||||
TypeVariable<?>[] typeParameters = resolvedType.getTypeParameters();
|
||||
Type[] arguments = type.getActualTypeArguments();
|
||||
|
||||
Map<TypeVariable<?>, Type> localTypeVariables = new HashMap<>(parent.getTypeVariableMap());
|
||||
|
||||
IntStream.range(0, typeParameters.length) //
|
||||
.mapToObj(it -> Pair.of(typeParameters[it], arguments[it])) //
|
||||
.filter(it -> !(it.getSecond() instanceof TypeVariable)) //
|
||||
.forEach(it -> localTypeVariables.put(it.getFirst(), it.getSecond()));
|
||||
|
||||
return localTypeVariables;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeDiscoverer#doGetMapValueType()
|
||||
@@ -267,4 +242,47 @@ class ParameterizedTypeInformation<T> extends ParentTypeAwareTypeInformation<T>
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the type variables to be used. Uses the parent's type variable map but overwrites variables locally
|
||||
* declared.
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
* @param resolvedType must not be {@literal null}.
|
||||
* @param parent must not be {@literal null}.
|
||||
* @return will never be {@literal null}.
|
||||
*/
|
||||
private static Map<TypeVariable<?>, Type> calculateTypeVariables(ParameterizedType type, Class<?> resolvedType,
|
||||
TypeDiscoverer<?> parent) {
|
||||
|
||||
TypeVariable<?>[] typeParameters = resolvedType.getTypeParameters();
|
||||
Type[] arguments = type.getActualTypeArguments();
|
||||
|
||||
Map<TypeVariable<?>, Type> localTypeVariables = new HashMap<>(parent.getTypeVariableMap());
|
||||
|
||||
IntStream.range(0, typeParameters.length) //
|
||||
.mapToObj(it -> Pair.of(typeParameters[it], flattenTypeVariable(arguments[it], localTypeVariables))) //
|
||||
.forEach(it -> localTypeVariables.put(it.getFirst(), it.getSecond()));
|
||||
|
||||
return localTypeVariables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively resolves the type bound to the given {@link Type} in case it's a {@link TypeVariable} and there's an
|
||||
* entry in the given type variables.
|
||||
*
|
||||
* @param source must not be {@literal null}.
|
||||
* @param variables must not be {@literal null}.
|
||||
* @return will never be {@literal null}.
|
||||
*/
|
||||
private static Type flattenTypeVariable(Type source, Map<TypeVariable<?>, Type> variables) {
|
||||
|
||||
if (!(source instanceof TypeVariable)) {
|
||||
return source;
|
||||
}
|
||||
|
||||
Type value = variables.get(source);
|
||||
|
||||
return value == null ? source : flattenTypeVariable(value, variables);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,7 +140,7 @@ class TypeDiscoverer<S> implements TypeInformation<S> {
|
||||
if (fieldType instanceof TypeVariable) {
|
||||
|
||||
TypeVariable<?> variable = (TypeVariable<?>) fieldType;
|
||||
return new TypeVariableTypeInformation(variable, type, this);
|
||||
return new TypeVariableTypeInformation(variable, this);
|
||||
}
|
||||
|
||||
if (fieldType instanceof GenericArrayType) {
|
||||
|
||||
@@ -17,7 +17,6 @@ package org.springframework.data.util;
|
||||
|
||||
import static org.springframework.util.ObjectUtils.*;
|
||||
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
|
||||
@@ -33,61 +32,22 @@ import org.springframework.util.Assert;
|
||||
class TypeVariableTypeInformation<T> extends ParentTypeAwareTypeInformation<T> {
|
||||
|
||||
private final TypeVariable<?> variable;
|
||||
private final Type owningType;
|
||||
|
||||
/**
|
||||
* Creates a bew {@link TypeVariableTypeInformation} for the given {@link TypeVariable} owning {@link Type} and parent
|
||||
* Creates a new {@link TypeVariableTypeInformation} for the given {@link TypeVariable} owning {@link Type} and parent
|
||||
* {@link TypeDiscoverer}.
|
||||
*
|
||||
* @param variable must not be {@literal null}
|
||||
* @param owningType must not be {@literal null}
|
||||
* @param parent
|
||||
*/
|
||||
public TypeVariableTypeInformation(TypeVariable<?> variable, Type owningType, TypeDiscoverer<?> parent) {
|
||||
public TypeVariableTypeInformation(TypeVariable<?> variable, TypeDiscoverer<?> parent) {
|
||||
|
||||
super(variable, parent);
|
||||
|
||||
Assert.notNull(variable, "TypeVariable must not be null!");
|
||||
|
||||
this.variable = variable;
|
||||
this.owningType = owningType;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.util.TypeDiscoverer#getType()
|
||||
*/
|
||||
@Override
|
||||
public Class<T> getType() {
|
||||
|
||||
int index = getIndex(variable);
|
||||
|
||||
if (owningType instanceof ParameterizedType && index != -1) {
|
||||
Type fieldType = ((ParameterizedType) owningType).getActualTypeArguments()[index];
|
||||
return resolveType(fieldType);
|
||||
}
|
||||
|
||||
return resolveType(variable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the type parameter binding the given {@link TypeVariable}.
|
||||
*
|
||||
* @param variable
|
||||
* @return
|
||||
*/
|
||||
private int getIndex(TypeVariable<?> variable) {
|
||||
|
||||
Class<?> rawType = resolveType(owningType);
|
||||
TypeVariable<?>[] typeParameters = rawType.getTypeParameters();
|
||||
|
||||
for (int i = 0; i < typeParameters.length; i++) {
|
||||
if (variable.equals(typeParameters[i])) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user