Enforce exact match for bounds of nested type variable
Closes gh-34300
This commit is contained in:
@@ -329,9 +329,6 @@ public class ResolvableType implements Serializable {
|
||||
other.getComponentType(), true, matchedBefore, upUntilUnresolvable));
|
||||
}
|
||||
|
||||
// We're checking nested generic variables now...
|
||||
boolean exactMatch = (strict && matchedBefore != null);
|
||||
|
||||
// Deal with wildcard bounds
|
||||
WildcardBounds ourBounds = WildcardBounds.get(this);
|
||||
WildcardBounds otherBounds = WildcardBounds.get(other);
|
||||
@@ -345,8 +342,9 @@ public class ResolvableType implements Serializable {
|
||||
else if (upUntilUnresolvable) {
|
||||
return otherBounds.isAssignableFrom(this, matchedBefore);
|
||||
}
|
||||
else if (!exactMatch) {
|
||||
return otherBounds.isAssignableTo(this, matchedBefore);
|
||||
else if (!strict) {
|
||||
return (matchedBefore != null ? otherBounds.equalsType(this) :
|
||||
otherBounds.isAssignableTo(this, matchedBefore));
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
@@ -359,6 +357,7 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
|
||||
// Main assignability check about to follow
|
||||
boolean exactMatch = (strict && matchedBefore != null);
|
||||
boolean checkGenerics = true;
|
||||
Class<?> ourResolved = null;
|
||||
if (this.type instanceof TypeVariable<?> variable) {
|
||||
@@ -1782,6 +1781,21 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return {@code true} if these bounds are equal to the specified type.
|
||||
* @param type the type to test against
|
||||
* @return {@code true} if these bounds are equal to the type
|
||||
* @since 6.2.3
|
||||
*/
|
||||
public boolean equalsType(ResolvableType type) {
|
||||
for (ResolvableType bound : this.bounds) {
|
||||
if (!type.equalsType(bound)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the underlying bounds.
|
||||
*/
|
||||
|
||||
@@ -1230,6 +1230,8 @@ class ResolvableTypeTests {
|
||||
ResolvableType consumerUnresolved = ResolvableType.forClass(Consumer.class);
|
||||
ResolvableType consumerObject = ResolvableType.forClassWithGenerics(Consumer.class, Object.class);
|
||||
ResolvableType consumerNestedUnresolved = ResolvableType.forClassWithGenerics(Consumer.class, ResolvableType.forClass(Consumer.class));
|
||||
ResolvableType consumerNumber = ResolvableType.forClassWithGenerics(Consumer.class, Number.class);
|
||||
ResolvableType consumerExtendsNumber = ResolvableType.forClass(SubConsumer.class);
|
||||
|
||||
assertThat(consumerUnresolved.isAssignableFrom(consumerObject)).isTrue();
|
||||
assertThat(consumerUnresolved.isAssignableFromResolvedPart(consumerObject)).isTrue();
|
||||
@@ -1239,6 +1241,10 @@ class ResolvableTypeTests {
|
||||
assertThat(consumerUnresolved.isAssignableFromResolvedPart(consumerNestedUnresolved)).isTrue();
|
||||
assertThat(consumerObject.isAssignableFrom(consumerNestedUnresolved)).isFalse();
|
||||
assertThat(consumerObject.isAssignableFromResolvedPart(consumerNestedUnresolved)).isFalse();
|
||||
assertThat(consumerObject.isAssignableFrom(consumerNumber)).isFalse();
|
||||
assertThat(consumerObject.isAssignableFromResolvedPart(consumerNumber)).isFalse();
|
||||
assertThat(consumerObject.isAssignableFrom(consumerExtendsNumber)).isFalse();
|
||||
assertThat(consumerObject.isAssignableFromResolvedPart(consumerExtendsNumber)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1788,6 +1794,9 @@ class ResolvableTypeTests {
|
||||
public interface Consumer<T> {
|
||||
}
|
||||
|
||||
private static class SubConsumer<N extends Number> implements Consumer<N> {
|
||||
}
|
||||
|
||||
public class Wildcard<T extends CharSequence> {
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user