DATACMNS-1135 - Fixed generics lookup for recursively nested container references.
Revert the merging of a parent type's type variable map and only apply the locally available declared generics in case of parameterized types. Moved that augmentation into ParameterizedTypeInformation.
This commit is contained in:
@@ -18,8 +18,6 @@ package org.springframework.data.util;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.GenericArrayType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
@@ -38,12 +36,10 @@ class GenericArrayTypeInformation<S> extends ParentTypeAwareTypeInformation<S> {
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
* @param parent must not be {@literal null}.
|
||||
* @param typeVariableMap must not be {@literal null}.
|
||||
*/
|
||||
protected GenericArrayTypeInformation(GenericArrayType type, TypeDiscoverer<?> parent,
|
||||
Map<TypeVariable<?>, Type> typeVariableMap) {
|
||||
protected GenericArrayTypeInformation(GenericArrayType type, TypeDiscoverer<?> parent) {
|
||||
|
||||
super(type, parent, typeVariableMap);
|
||||
super(type, parent);
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,11 +21,13 @@ import java.lang.reflect.TypeVariable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -49,15 +51,39 @@ class ParameterizedTypeInformation<T> extends ParentTypeAwareTypeInformation<T>
|
||||
* @param type must not be {@literal null}
|
||||
* @param parent must not be {@literal null}
|
||||
*/
|
||||
public ParameterizedTypeInformation(ParameterizedType type, TypeDiscoverer<?> parent,
|
||||
Map<TypeVariable<?>, Type> typeVariableMap) {
|
||||
public ParameterizedTypeInformation(ParameterizedType type, Class<?> resolvedType, TypeDiscoverer<?> parent) {
|
||||
|
||||
super(type, parent, typeVariableMap);
|
||||
super(type, parent, calculateTypeVariables(type, resolvedType, parent));
|
||||
|
||||
this.type = type;
|
||||
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()
|
||||
|
||||
@@ -17,7 +17,6 @@ package org.springframework.data.util;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
@@ -37,28 +36,15 @@ public abstract class ParentTypeAwareTypeInformation<S> extends TypeDiscoverer<S
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
* @param parent must not be {@literal null}.
|
||||
* @param map must not be {@literal null}.
|
||||
*/
|
||||
protected ParentTypeAwareTypeInformation(Type type, TypeDiscoverer<?> parent, Map<TypeVariable<?>, Type> map) {
|
||||
|
||||
super(type, mergeMaps(parent, map));
|
||||
this.parent = parent;
|
||||
protected ParentTypeAwareTypeInformation(Type type, TypeDiscoverer<?> parent) {
|
||||
this(type, parent, parent.getTypeVariableMap());
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges the type variable maps of the given parent with the new map.
|
||||
*
|
||||
* @param parent must not be {@literal null}.
|
||||
* @param map must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
private static Map<TypeVariable<?>, Type> mergeMaps(TypeDiscoverer<?> parent, Map<TypeVariable<?>, Type> map) {
|
||||
protected ParentTypeAwareTypeInformation(Type type, TypeDiscoverer<?> parent, Map<TypeVariable<?>, Type> map) {
|
||||
|
||||
Map<TypeVariable<?>, Type> typeVariableMap = new HashMap<>();
|
||||
typeVariableMap.putAll(map);
|
||||
typeVariableMap.putAll(parent.getTypeVariableMap());
|
||||
|
||||
return typeVariableMap;
|
||||
super(type, map);
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -129,31 +129,22 @@ class TypeDiscoverer<S> implements TypeInformation<S> {
|
||||
return ClassTypeInformation.from((Class<?>) fieldType);
|
||||
}
|
||||
|
||||
Class<S> resolveType = resolveType(fieldType);
|
||||
Map<TypeVariable, Type> variableMap = new HashMap<>();
|
||||
variableMap.putAll(GenericTypeResolver.getTypeVariableMap(resolveType));
|
||||
Class<S> resolvedType = resolveType(fieldType);
|
||||
|
||||
if (fieldType instanceof ParameterizedType) {
|
||||
|
||||
ParameterizedType parameterizedType = (ParameterizedType) fieldType;
|
||||
|
||||
TypeVariable<Class<S>>[] typeParameters = resolveType.getTypeParameters();
|
||||
Type[] arguments = parameterizedType.getActualTypeArguments();
|
||||
|
||||
for (int i = 0; i < typeParameters.length; i++) {
|
||||
variableMap.put(typeParameters[i], arguments[i]);
|
||||
}
|
||||
|
||||
return new ParameterizedTypeInformation(parameterizedType, this, variableMap);
|
||||
return new ParameterizedTypeInformation(parameterizedType, resolvedType, this);
|
||||
}
|
||||
|
||||
if (fieldType instanceof TypeVariable) {
|
||||
|
||||
TypeVariable<?> variable = (TypeVariable<?>) fieldType;
|
||||
return new TypeVariableTypeInformation(variable, type, this, variableMap);
|
||||
return new TypeVariableTypeInformation(variable, type, this);
|
||||
}
|
||||
|
||||
if (fieldType instanceof GenericArrayType) {
|
||||
return new GenericArrayTypeInformation((GenericArrayType) fieldType, this, variableMap);
|
||||
return new GenericArrayTypeInformation((GenericArrayType) fieldType, this);
|
||||
}
|
||||
|
||||
if (fieldType instanceof WildcardType) {
|
||||
|
||||
@@ -20,7 +20,6 @@ import static org.springframework.util.ObjectUtils.*;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -44,11 +43,12 @@ class TypeVariableTypeInformation<T> extends ParentTypeAwareTypeInformation<T> {
|
||||
* @param owningType must not be {@literal null}
|
||||
* @param parent
|
||||
*/
|
||||
public TypeVariableTypeInformation(TypeVariable<?> variable, Type owningType, TypeDiscoverer<?> parent,
|
||||
Map<TypeVariable<?>, Type> typeVariableMap) {
|
||||
public TypeVariableTypeInformation(TypeVariable<?> variable, Type owningType, TypeDiscoverer<?> parent) {
|
||||
|
||||
super(variable, parent);
|
||||
|
||||
super(variable, parent, typeVariableMap);
|
||||
Assert.notNull(variable, "TypeVariable must not be null!");
|
||||
|
||||
this.variable = variable;
|
||||
this.owningType = owningType;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user