Restrict lenient nested matching to immediate type variable
Includes fix for matching multiple wildcard bounds properly. Closes gh-34119 Closes gh-34234
This commit is contained in:
parent
d280358e98
commit
227385083d
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -410,8 +410,9 @@ public class ResolvableType implements Serializable {
|
|||
}
|
||||
matchedBefore.put(this.type, other.type);
|
||||
for (int i = 0; i < ourGenerics.length; i++) {
|
||||
if (!ourGenerics[i].isAssignableFrom(otherGenerics[i],
|
||||
!other.hasUnresolvableGenerics(), matchedBefore, upUntilUnresolvable)) {
|
||||
ResolvableType otherGeneric = otherGenerics[i];
|
||||
if (!ourGenerics[i].isAssignableFrom(otherGeneric,
|
||||
!otherGeneric.isUnresolvableTypeVariable(), matchedBefore, upUntilUnresolvable)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1729,8 +1730,16 @@ public class ResolvableType implements Serializable {
|
|||
* @return {@code true} if these bounds are assignable from all types
|
||||
*/
|
||||
public boolean isAssignableFrom(ResolvableType[] types, @Nullable Map<Type, Type> matchedBefore) {
|
||||
for (ResolvableType type : types) {
|
||||
if (!isAssignableFrom(type, matchedBefore)) {
|
||||
for (ResolvableType bound : this.bounds) {
|
||||
boolean matched = false;
|
||||
for (ResolvableType type : types) {
|
||||
if (this.kind == Kind.UPPER ? bound.isAssignableFrom(type, false, matchedBefore, false) :
|
||||
type.isAssignableFrom(bound, false, matchedBefore, false)) {
|
||||
matched = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!matched) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -1189,10 +1189,11 @@ class ResolvableTypeTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
void isAssignableFromForUnresolvedWildcards() {
|
||||
void isAssignableFromForUnresolvedWildcard() {
|
||||
ResolvableType wildcard = ResolvableType.forInstance(new Wildcard<>());
|
||||
ResolvableType wildcardFixed = ResolvableType.forInstance(new WildcardFixed());
|
||||
ResolvableType wildcardConcrete = ResolvableType.forClassWithGenerics(Wildcard.class, Number.class);
|
||||
ResolvableType wildcardConcrete = ResolvableType.forClassWithGenerics(Wildcard.class, CharSequence.class);
|
||||
ResolvableType wildcardConsumer = ResolvableType.forInstance(new WildcardConsumer<>());
|
||||
|
||||
assertThat(wildcard.isAssignableFrom(wildcardFixed)).isTrue();
|
||||
assertThat(wildcard.isAssignableFromResolvedPart(wildcardFixed)).isTrue();
|
||||
|
@ -1206,6 +1207,38 @@ class ResolvableTypeTests {
|
|||
assertThat(wildcardConcrete.isAssignableFromResolvedPart(wildcard)).isTrue();
|
||||
assertThat(wildcardConcrete.isAssignableFrom(wildcardFixed)).isFalse();
|
||||
assertThat(wildcardConcrete.isAssignableFromResolvedPart(wildcardFixed)).isFalse();
|
||||
assertThat(wildcardConsumer.as(Consumer.class).getGeneric().isAssignableFrom(wildcard)).isFalse();
|
||||
assertThat(wildcardConsumer.as(Consumer.class).getGeneric().isAssignableFromResolvedPart(wildcard)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void isAssignableFromForUnresolvedDoubleWildcard() {
|
||||
ResolvableType wildcard = ResolvableType.forInstance(new DoubleWildcard<>());
|
||||
ResolvableType wildcardFixed = ResolvableType.forInstance(new DoubleWildcardFixed());
|
||||
ResolvableType wildcardConsumer = ResolvableType.forInstance(new DoubleWildcardConsumer<>());
|
||||
|
||||
assertThat(wildcard.isAssignableFrom(wildcardFixed)).isTrue();
|
||||
assertThat(wildcard.isAssignableFromResolvedPart(wildcardFixed)).isTrue();
|
||||
assertThat(wildcardFixed.isAssignableFrom(wildcard)).isFalse();
|
||||
assertThat(wildcardFixed.isAssignableFromResolvedPart(wildcard)).isFalse();
|
||||
assertThat(wildcardConsumer.as(Consumer.class).getGeneric().isAssignableFrom(wildcard)).isTrue();
|
||||
assertThat(wildcardConsumer.as(Consumer.class).getGeneric().isAssignableFromResolvedPart(wildcard)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void strictGenericsMatching() {
|
||||
ResolvableType consumerUnresolved = ResolvableType.forClass(Consumer.class);
|
||||
ResolvableType consumerObject = ResolvableType.forClassWithGenerics(Consumer.class, Object.class);
|
||||
ResolvableType consumerNestedUnresolved = ResolvableType.forClassWithGenerics(Consumer.class, ResolvableType.forClass(Consumer.class));
|
||||
|
||||
assertThat(consumerUnresolved.isAssignableFrom(consumerObject)).isTrue();
|
||||
assertThat(consumerUnresolved.isAssignableFromResolvedPart(consumerObject)).isTrue();
|
||||
assertThat(consumerObject.isAssignableFrom(consumerUnresolved)).isTrue();
|
||||
assertThat(consumerObject.isAssignableFromResolvedPart(consumerUnresolved)).isTrue();
|
||||
assertThat(consumerUnresolved.isAssignableFrom(consumerNestedUnresolved)).isTrue();
|
||||
assertThat(consumerUnresolved.isAssignableFromResolvedPart(consumerNestedUnresolved)).isTrue();
|
||||
assertThat(consumerObject.isAssignableFrom(consumerNestedUnresolved)).isFalse();
|
||||
assertThat(consumerObject.isAssignableFromResolvedPart(consumerNestedUnresolved)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1752,12 +1785,26 @@ class ResolvableTypeTests {
|
|||
}
|
||||
|
||||
|
||||
public class Wildcard<T extends Number> {
|
||||
public class Wildcard<T extends CharSequence> {
|
||||
}
|
||||
|
||||
public class WildcardFixed extends Wildcard<Integer> {
|
||||
public class WildcardFixed extends Wildcard<String> {
|
||||
}
|
||||
|
||||
public class WildcardConsumer<T extends CharSequence & Serializable> implements Consumer<Wildcard<T>> {
|
||||
}
|
||||
|
||||
|
||||
public class DoubleWildcard<T extends CharSequence & Serializable> {
|
||||
}
|
||||
|
||||
public class DoubleWildcardFixed extends DoubleWildcard<String> {
|
||||
}
|
||||
|
||||
public class DoubleWildcardConsumer<T extends CharSequence & Serializable> implements Consumer<DoubleWildcard<T>> {
|
||||
}
|
||||
|
||||
|
||||
|
||||
interface VariableNameSwitch<V, K> extends MultiValueMap<K, V> {
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue