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, Create { + } + }