Browse Source

Merge branch '6.2.x'

pull/34399/head
Juergen Hoeller 1 year ago
parent
commit
4ba14ca58c
  1. 5
      spring-core/src/main/java/org/springframework/core/GenericTypeResolver.java
  2. 4
      spring-core/src/main/java/org/springframework/core/ResolvableType.java
  3. 51
      spring-core/src/test/java/org/springframework/core/GenericTypeResolverTests.java

5
spring-core/src/main/java/org/springframework/core/GenericTypeResolver.java

@ -166,8 +166,8 @@ public final class GenericTypeResolver { @@ -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 { @@ -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;
}
}

4
spring-core/src/main/java/org/springframework/core/ResolvableType.java

@ -951,10 +951,10 @@ public class ResolvableType implements Serializable { @@ -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();

51
spring-core/src/test/java/org/springframework/core/GenericTypeResolverTests.java

@ -18,20 +18,25 @@ package org.springframework.core; @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -398,9 +415,15 @@ class GenericTypeResolverTests {
}
interface Repository<T, ID extends Serializable> {
default void store(Supplier<T> t) {
}
}
interface IdFixingRepository<V> extends Repository<V, Long> {
}
interface IdFixingRepository<T> extends Repository<T, Long> {
static class ConcreteRepository implements IdFixingRepository<String> {
}
static class WithMethodParameter {

Loading…
Cancel
Save