mirror of
https://github.com/spring-projects/spring-framework.git
synced 2026-09-26 08:59:09 +00:00
Resolve against type variable from same declaration if possible
Closes gh-36890
This commit is contained in:
@@ -943,8 +943,9 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
private @Nullable ResolvableType resolveVariable(TypeVariable<?> variable) {
|
||||
TypeVariable<?> variableToCompare = SerializableTypeWrapper.unwrap(variable);
|
||||
if (this.type instanceof TypeVariable) {
|
||||
return resolveType().resolveVariable(variable);
|
||||
return resolveType().resolveVariable(variableToCompare);
|
||||
}
|
||||
if (this.type instanceof ParameterizedType parameterizedType) {
|
||||
Class<?> resolved = resolve();
|
||||
@@ -954,23 +955,29 @@ public class ResolvableType implements Serializable {
|
||||
TypeVariable<?>[] variables = resolved.getTypeParameters();
|
||||
Type[] typeArguments = parameterizedType.getActualTypeArguments();
|
||||
for (int i = 0; i < variables.length; i++) {
|
||||
if (ObjectUtils.nullSafeEquals(variables[i].getName(), variable.getName())) {
|
||||
if (ObjectUtils.nullSafeEquals(variables[i], variableToCompare)) {
|
||||
return forType(typeArguments[i], this.variableResolver);
|
||||
}
|
||||
}
|
||||
Type ownerType = parameterizedType.getOwnerType();
|
||||
if (ownerType != null) {
|
||||
return forType(ownerType, this.variableResolver).resolveVariable(variable);
|
||||
return forType(ownerType, this.variableResolver).resolveVariable(variableToCompare);
|
||||
}
|
||||
// Fallback: comparison by variable name, independent of generic declaration context.
|
||||
for (int i = 0; i < variables.length; i++) {
|
||||
if (ObjectUtils.nullSafeEquals(variables[i].getName(), variableToCompare.getName())) {
|
||||
return forType(typeArguments[i], this.variableResolver);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.type instanceof WildcardType) {
|
||||
ResolvableType resolved = resolveType().resolveVariable(variable);
|
||||
ResolvableType resolved = resolveType().resolveVariable(variableToCompare);
|
||||
if (resolved != null) {
|
||||
return resolved;
|
||||
}
|
||||
}
|
||||
if (this.variableResolver != null) {
|
||||
return this.variableResolver.resolveVariable(variable);
|
||||
return this.variableResolver.resolveVariable(variableToCompare);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -1616,8 +1623,7 @@ public class ResolvableType implements Serializable {
|
||||
public @Nullable ResolvableType resolveVariable(TypeVariable<?> variable) {
|
||||
TypeVariable<?> variableToCompare = SerializableTypeWrapper.unwrap(variable);
|
||||
for (int i = 0; i < this.variables.length; i++) {
|
||||
TypeVariable<?> resolvedVariable = SerializableTypeWrapper.unwrap(this.variables[i]);
|
||||
if (ObjectUtils.nullSafeEquals(resolvedVariable, variableToCompare)) {
|
||||
if (ObjectUtils.nullSafeEquals(this.variables[i], variableToCompare)) {
|
||||
return this.generics[i];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,7 +251,7 @@ class GenericTypeResolverTests {
|
||||
assertThat(resolvedType).isEqualTo(InheritsDefaultMethod.ConcreteType.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test // gh-36480
|
||||
void resolveTypeFromNestedParameterizedType() {
|
||||
Type resolvedType = resolveType(method(MyInterfaceType.class, "get").getGenericReturnType(), MyCollectionInterfaceType.class);
|
||||
assertThat(resolvedType).isEqualTo(method(MyCollectionInterfaceType.class, "get").getGenericReturnType());
|
||||
@@ -260,6 +260,12 @@ class GenericTypeResolverTests {
|
||||
assertThat(resolvedType).isEqualTo(method(MyOptionalInterfaceType.class, "get").getGenericReturnType());
|
||||
}
|
||||
|
||||
@Test // gh-36890
|
||||
void resolveTypeAgainstSameNamedVariables() {
|
||||
Type resolvedType = resolveType(method(Create.class, "create", Object.class).getGenericParameterTypes()[0], Controller.class);
|
||||
assertThat(resolvedType).isEqualTo(Long.class);
|
||||
}
|
||||
|
||||
private static Method method(Class<?> target, String methodName, Class<?>... parameterTypes) {
|
||||
Method method = findMethod(target, methodName, parameterTypes);
|
||||
assertThat(method).describedAs(target.getName() + "#" + methodName).isNotNull();
|
||||
@@ -504,4 +510,16 @@ class GenericTypeResolverTests {
|
||||
}
|
||||
}
|
||||
|
||||
interface Search<I, O> {
|
||||
}
|
||||
|
||||
interface Create<I, O> {
|
||||
default O create(I body) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static class Controller implements Search<String, Long>, Create<Long, Long> {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user