diff --git a/spring-core/src/main/java/org/springframework/core/ResolvableType.java b/spring-core/src/main/java/org/springframework/core/ResolvableType.java index 5a6fae09bb..d8d4ac98e7 100644 --- a/spring-core/src/main/java/org/springframework/core/ResolvableType.java +++ b/spring-core/src/main/java/org/springframework/core/ResolvableType.java @@ -334,19 +334,19 @@ public class ResolvableType implements Serializable { // Deal with wildcard bounds WildcardBounds ourBounds = WildcardBounds.get(this); - WildcardBounds typeBounds = WildcardBounds.get(other); + WildcardBounds otherBounds = WildcardBounds.get(other); // In the form X is assignable to - if (typeBounds != null) { + if (otherBounds != null) { if (ourBounds != null) { - return (ourBounds.isSameKind(typeBounds) && - ourBounds.isAssignableFrom(typeBounds.getBounds(), matchedBefore)); + return (ourBounds.isSameKind(otherBounds) && + ourBounds.isAssignableFrom(otherBounds.getBounds(), matchedBefore)); } else if (upUntilUnresolvable) { - return typeBounds.isAssignableFrom(this, matchedBefore); + return otherBounds.isAssignableFrom(this, matchedBefore); } else if (!exactMatch) { - return typeBounds.isAssignableTo(this, matchedBefore); + return otherBounds.isAssignableTo(this, matchedBefore); } else { return false; @@ -400,8 +400,8 @@ public class ResolvableType implements Serializable { if (checkGenerics) { // Recursively check each generic ResolvableType[] ourGenerics = getGenerics(); - ResolvableType[] typeGenerics = other.as(ourResolved).getGenerics(); - if (ourGenerics.length != typeGenerics.length) { + ResolvableType[] otherGenerics = other.as(ourResolved).getGenerics(); + if (ourGenerics.length != otherGenerics.length) { return false; } if (ourGenerics.length > 0) { @@ -410,7 +410,8 @@ public class ResolvableType implements Serializable { } matchedBefore.put(this.type, other.type); for (int i = 0; i < ourGenerics.length; i++) { - if (!ourGenerics[i].isAssignableFrom(typeGenerics[i], true, matchedBefore, upUntilUnresolvable)) { + if (!ourGenerics[i].isAssignableFrom(otherGenerics[i], + !other.hasUnresolvableGenerics(), matchedBefore, upUntilUnresolvable)) { return false; } } diff --git a/spring-core/src/test/java/org/springframework/core/ResolvableTypeTests.java b/spring-core/src/test/java/org/springframework/core/ResolvableTypeTests.java index 6769232581..3af9b1fdee 100644 --- a/spring-core/src/test/java/org/springframework/core/ResolvableTypeTests.java +++ b/spring-core/src/test/java/org/springframework/core/ResolvableTypeTests.java @@ -1188,6 +1188,26 @@ class ResolvableTypeTests { assertThatResolvableType(complex4).isNotAssignableFrom(complex3); } + @Test + void isAssignableFromForUnresolvedWildcards() { + ResolvableType wildcard = ResolvableType.forInstance(new Wildcard<>()); + ResolvableType wildcardFixed = ResolvableType.forInstance(new WildcardFixed()); + ResolvableType wildcardConcrete = ResolvableType.forClassWithGenerics(Wildcard.class, Number.class); + + assertThat(wildcard.isAssignableFrom(wildcardFixed)).isTrue(); + assertThat(wildcard.isAssignableFromResolvedPart(wildcardFixed)).isTrue(); + assertThat(wildcard.isAssignableFrom(wildcardConcrete)).isTrue(); + assertThat(wildcard.isAssignableFromResolvedPart(wildcardConcrete)).isTrue(); + assertThat(wildcardFixed.isAssignableFrom(wildcard)).isFalse(); + assertThat(wildcardFixed.isAssignableFromResolvedPart(wildcard)).isFalse(); + assertThat(wildcardFixed.isAssignableFrom(wildcardConcrete)).isFalse(); + assertThat(wildcardFixed.isAssignableFromResolvedPart(wildcardConcrete)).isFalse(); + assertThat(wildcardConcrete.isAssignableFrom(wildcard)).isTrue(); + assertThat(wildcardConcrete.isAssignableFromResolvedPart(wildcard)).isTrue(); + assertThat(wildcardConcrete.isAssignableFrom(wildcardFixed)).isFalse(); + assertThat(wildcardConcrete.isAssignableFromResolvedPart(wildcardFixed)).isFalse(); + } + @Test void identifyTypeVariable() throws Exception { Method method = ClassArguments.class.getMethod("typedArgumentFirst", Class.class, Class.class, Class.class); @@ -1685,7 +1705,6 @@ class ResolvableTypeTests { } } - public class MySimpleInterfaceType implements MyInterfaceType { } @@ -1695,7 +1714,6 @@ class ResolvableTypeTests { public abstract class ExtendsMySimpleInterfaceTypeWithImplementsRaw extends MySimpleInterfaceTypeWithImplementsRaw { } - public class MyCollectionInterfaceType implements MyInterfaceType> { } @@ -1703,20 +1721,17 @@ class ResolvableTypeTests { public abstract class MySuperclassType { } - public class MySimpleSuperclassType extends MySuperclassType { } - public class MyCollectionSuperclassType extends MySuperclassType> { } - interface Wildcard extends List { + public class Wildcard { } - - interface RawExtendsWildcard extends Wildcard { + public class WildcardFixed extends Wildcard { }