diff --git a/spring-core/src/main/java/org/springframework/core/GenericTypeResolver.java b/spring-core/src/main/java/org/springframework/core/GenericTypeResolver.java index 083964732733..c45fe7f26283 100644 --- a/spring-core/src/main/java/org/springframework/core/GenericTypeResolver.java +++ b/spring-core/src/main/java/org/springframework/core/GenericTypeResolver.java @@ -209,7 +209,7 @@ else if (typeArgument instanceof ParameterizedType) { private static ResolvableType resolveVariable(TypeVariable> typeVariable, ResolvableType contextType) { ResolvableType resolvedType; - if (contextType.hasGenerics()) { + if (contextType.hasGenerics() && declaresTypeVariable(typeVariable, contextType)) { ResolvableType.VariableResolver variableResolver = contextType.asVariableResolver(); if (variableResolver == null) { return ResolvableType.NONE; @@ -239,6 +239,11 @@ private static ResolvableType resolveVariable(TypeVariable> typeVariable, Reso return ResolvableType.NONE; } + private static boolean declaresTypeVariable(TypeVariable> typeVariable, ResolvableType contextType) { + TypeVariable> variableToCompare = SerializableTypeWrapper.unwrap(typeVariable); + return (variableToCompare.getGenericDeclaration() == contextType.resolve()); + } + /** * Resolve the specified generic type against the given TypeVariable map. *
Used by Spring Data.
diff --git a/spring-core/src/test/java/org/springframework/core/GenericTypeResolverTests.java b/spring-core/src/test/java/org/springframework/core/GenericTypeResolverTests.java
index 7e4e3542c021..639e0844e7c8 100644
--- a/spring-core/src/test/java/org/springframework/core/GenericTypeResolverTests.java
+++ b/spring-core/src/test/java/org/springframework/core/GenericTypeResolverTests.java
@@ -251,6 +251,14 @@ void resolveTypeFromGenericDefaultMethod() {
assertThat(resolvedType).isEqualTo(InheritsDefaultMethod.ConcreteType.class);
}
+ @Test // gh-36890
+ void resolveTypeVariableCollisionAcrossInterfaces() {
+ Type type = method(Create.class, "create", Object.class).getGenericParameterTypes()[0];
+ Type resolvedType = resolveType(type, Controller.class);
+
+ assertThat(resolvedType).isEqualTo(Long.class);
+ }
+
@Test
void resolveTypeFromNestedParameterizedType() {
Type resolvedType = resolveType(method(MyInterfaceType.class, "get").getGenericReturnType(), MyCollectionInterfaceType.class);
@@ -504,4 +512,17 @@ static class ConcreteType implements InterfaceWithDefaultMethod.AbstractType {
}
}
+ interface Search {
+ }
+
+ interface Create {
+
+ default O create(I body) {
+ return null;
+ }
+ }
+
+ static class Controller implements Search