Merge branch '6.2.x'
This commit is contained in:
@@ -166,8 +166,8 @@ public final class GenericTypeResolver {
|
||||
else if (genericType instanceof ParameterizedType parameterizedType) {
|
||||
ResolvableType resolvedType = ResolvableType.forType(genericType);
|
||||
if (resolvedType.hasUnresolvableGenerics()) {
|
||||
ResolvableType[] generics = new ResolvableType[parameterizedType.getActualTypeArguments().length];
|
||||
Type[] typeArguments = parameterizedType.getActualTypeArguments();
|
||||
ResolvableType[] generics = new ResolvableType[typeArguments.length];
|
||||
ResolvableType contextType = ResolvableType.forClass(contextClass);
|
||||
for (int i = 0; i < typeArguments.length; i++) {
|
||||
Type typeArgument = typeArguments[i];
|
||||
@@ -206,6 +206,9 @@ public final class GenericTypeResolver {
|
||||
}
|
||||
resolvedType = variableResolver.resolveVariable(typeVariable);
|
||||
if (resolvedType != null) {
|
||||
while (resolvedType.getType() instanceof TypeVariable<?>) {
|
||||
resolvedType = resolvedType.resolveType();
|
||||
}
|
||||
return resolvedType;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -951,10 +951,10 @@ public class ResolvableType implements Serializable {
|
||||
return null;
|
||||
}
|
||||
TypeVariable<?>[] variables = resolved.getTypeParameters();
|
||||
Type[] typeArguments = parameterizedType.getActualTypeArguments();
|
||||
for (int i = 0; i < variables.length; i++) {
|
||||
if (ObjectUtils.nullSafeEquals(variables[i].getName(), variable.getName())) {
|
||||
Type actualType = parameterizedType.getActualTypeArguments()[i];
|
||||
return forType(actualType, this.variableResolver);
|
||||
return forType(typeArguments[i], this.variableResolver);
|
||||
}
|
||||
}
|
||||
Type ownerType = parameterizedType.getOwnerType();
|
||||
|
||||
@@ -18,20 +18,25 @@ package org.springframework.core;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
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;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.core.GenericTypeResolver.getTypeVariableMap;
|
||||
import static org.springframework.core.GenericTypeResolver.resolveParameterType;
|
||||
import static org.springframework.core.GenericTypeResolver.resolveReturnType;
|
||||
import static org.springframework.core.GenericTypeResolver.resolveReturnTypeArgument;
|
||||
import static org.springframework.core.GenericTypeResolver.resolveType;
|
||||
import static org.springframework.core.GenericTypeResolver.resolveTypeArgument;
|
||||
import static org.springframework.core.GenericTypeResolver.resolveTypeArguments;
|
||||
import static org.springframework.util.ReflectionUtils.findMethod;
|
||||
|
||||
/**
|
||||
@@ -106,25 +111,25 @@ class GenericTypeResolverTests {
|
||||
void testGetTypeVariableMap() {
|
||||
Map<TypeVariable, Type> map;
|
||||
|
||||
map = GenericTypeResolver.getTypeVariableMap(MySimpleInterfaceType.class);
|
||||
map = getTypeVariableMap(MySimpleInterfaceType.class);
|
||||
assertThat(map.toString()).isEqualTo("{T=class java.lang.String}");
|
||||
|
||||
map = GenericTypeResolver.getTypeVariableMap(MyCollectionInterfaceType.class);
|
||||
map = getTypeVariableMap(MyCollectionInterfaceType.class);
|
||||
assertThat(map.toString()).isEqualTo("{T=java.util.Collection<java.lang.String>}");
|
||||
|
||||
map = GenericTypeResolver.getTypeVariableMap(MyCollectionSuperclassType.class);
|
||||
map = getTypeVariableMap(MyCollectionSuperclassType.class);
|
||||
assertThat(map.toString()).isEqualTo("{T=java.util.Collection<java.lang.String>}");
|
||||
|
||||
map = GenericTypeResolver.getTypeVariableMap(MySimpleTypeWithMethods.class);
|
||||
map = getTypeVariableMap(MySimpleTypeWithMethods.class);
|
||||
assertThat(map.toString()).isEqualTo("{T=class java.lang.Integer}");
|
||||
|
||||
map = GenericTypeResolver.getTypeVariableMap(TopLevelClass.class);
|
||||
map = getTypeVariableMap(TopLevelClass.class);
|
||||
assertThat(map.toString()).isEqualTo("{}");
|
||||
|
||||
map = GenericTypeResolver.getTypeVariableMap(TypedTopLevelClass.class);
|
||||
map = getTypeVariableMap(TypedTopLevelClass.class);
|
||||
assertThat(map.toString()).isEqualTo("{T=class java.lang.Integer}");
|
||||
|
||||
map = GenericTypeResolver.getTypeVariableMap(TypedTopLevelClass.TypedNested.class);
|
||||
map = getTypeVariableMap(TypedTopLevelClass.TypedNested.class);
|
||||
assertThat(map).hasSize(2);
|
||||
Type t = null;
|
||||
Type x = null;
|
||||
@@ -142,19 +147,19 @@ class GenericTypeResolverTests {
|
||||
|
||||
@Test
|
||||
void resolveTypeArgumentsOfAbstractType() {
|
||||
Class<?>[] resolved = GenericTypeResolver.resolveTypeArguments(MyConcreteType.class, MyAbstractType.class);
|
||||
Class<?>[] resolved = resolveTypeArguments(MyConcreteType.class, MyAbstractType.class);
|
||||
assertThat(resolved).containsExactly(Character.class);
|
||||
}
|
||||
|
||||
@Test // SPR-11030
|
||||
void getGenericsCannotBeResolved() {
|
||||
Class<?>[] resolved = GenericTypeResolver.resolveTypeArguments(List.class, Iterable.class);
|
||||
Class<?>[] resolved = resolveTypeArguments(List.class, Iterable.class);
|
||||
assertThat(resolved).isNull();
|
||||
}
|
||||
|
||||
@Test // SPR-11052
|
||||
void getRawMapTypeCannotBeResolved() {
|
||||
Class<?>[] resolved = GenericTypeResolver.resolveTypeArguments(Map.class, Map.class);
|
||||
Class<?>[] resolved = resolveTypeArguments(Map.class, Map.class);
|
||||
assertThat(resolved).isNull();
|
||||
}
|
||||
|
||||
@@ -163,26 +168,38 @@ class GenericTypeResolverTests {
|
||||
void getGenericsOnArrayFromParamCannotBeResolved() throws Exception {
|
||||
MethodParameter methodParameter = MethodParameter.forExecutable(
|
||||
WithArrayBase.class.getDeclaredMethod("array", Object[].class), 0);
|
||||
Class<?> resolved = GenericTypeResolver.resolveParameterType(methodParameter, WithArray.class);
|
||||
Class<?> resolved = resolveParameterType(methodParameter, WithArray.class);
|
||||
assertThat(resolved).isEqualTo(Object[].class);
|
||||
}
|
||||
|
||||
@Test // SPR-11044
|
||||
void getGenericsOnArrayFromReturnCannotBeResolved() throws Exception {
|
||||
Class<?> resolved = GenericTypeResolver.resolveReturnType(
|
||||
Class<?> resolved = resolveReturnType(
|
||||
WithArrayBase.class.getDeclaredMethod("array", Object[].class), WithArray.class);
|
||||
assertThat(resolved).isEqualTo(Object[].class);
|
||||
}
|
||||
|
||||
@Test // SPR-11763
|
||||
void resolveIncompleteTypeVariables() {
|
||||
Class<?>[] resolved = GenericTypeResolver.resolveTypeArguments(IdFixingRepository.class, Repository.class);
|
||||
Class<?>[] resolved = resolveTypeArguments(IdFixingRepository.class, Repository.class);
|
||||
assertThat(resolved).isNotNull();
|
||||
assertThat(resolved).hasSize(2);
|
||||
assertThat(resolved[0]).isEqualTo(Object.class);
|
||||
assertThat(resolved[1]).isEqualTo(Long.class);
|
||||
}
|
||||
|
||||
@Test // gh-34386
|
||||
void resolveVariableNameChange() {
|
||||
Type resolved = resolveType(Repository.class.getTypeParameters()[0], ConcreteRepository.class);
|
||||
assertThat(resolved).isEqualTo(String.class);
|
||||
Method method = method(Repository.class,"store", Supplier.class);
|
||||
resolved = resolveType(method.getGenericParameterTypes()[0], ConcreteRepository.class);
|
||||
assertThat(resolved).isInstanceOf(ParameterizedType.class);
|
||||
ParameterizedType pt = (ParameterizedType) resolved;
|
||||
assertThat(pt.getRawType()).isEqualTo(Supplier.class);
|
||||
assertThat(pt.getActualTypeArguments()[0]).isEqualTo(String.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void resolvePartiallySpecializedTypeVariables() {
|
||||
Type resolved = resolveType(BiGenericClass.class.getTypeParameters()[0], TypeFixedBiGenericClass.class);
|
||||
@@ -398,9 +415,15 @@ class GenericTypeResolverTests {
|
||||
}
|
||||
|
||||
interface Repository<T, ID extends Serializable> {
|
||||
|
||||
default void store(Supplier<T> t) {
|
||||
}
|
||||
}
|
||||
|
||||
interface IdFixingRepository<T> extends Repository<T, Long> {
|
||||
interface IdFixingRepository<V> extends Repository<V, Long> {
|
||||
}
|
||||
|
||||
static class ConcreteRepository implements IdFixingRepository<String> {
|
||||
}
|
||||
|
||||
static class WithMethodParameter {
|
||||
|
||||
Reference in New Issue
Block a user