Consistent Class and array matching with Class comparison shortcut
Closes gh-31487
This commit is contained in:
@@ -262,7 +262,9 @@ public class ResolvableType implements Serializable {
|
||||
* @see #isAssignableFrom(ResolvableType)
|
||||
*/
|
||||
public boolean isAssignableFrom(Class<?> other) {
|
||||
return isAssignableFrom(forClass(other), null);
|
||||
// As of 6.1: shortcut assignability check for top-level Class references
|
||||
return (this.type instanceof Class<?> clazz ? ClassUtils.isAssignable(clazz, other) :
|
||||
isAssignableFrom(forClass(other), false, null));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -277,10 +279,10 @@ public class ResolvableType implements Serializable {
|
||||
* {@code ResolvableType}; {@code false} otherwise
|
||||
*/
|
||||
public boolean isAssignableFrom(ResolvableType other) {
|
||||
return isAssignableFrom(other, null);
|
||||
return isAssignableFrom(other, false, null);
|
||||
}
|
||||
|
||||
private boolean isAssignableFrom(ResolvableType other, @Nullable Map<Type, Type> matchedBefore) {
|
||||
private boolean isAssignableFrom(ResolvableType other, boolean strict, @Nullable Map<Type, Type> matchedBefore) {
|
||||
Assert.notNull(other, "ResolvableType must not be null");
|
||||
|
||||
// If we cannot resolve types, we are not assignable
|
||||
@@ -288,13 +290,21 @@ public class ResolvableType implements Serializable {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Deal with array by delegating to the component type
|
||||
if (isArray()) {
|
||||
return (other.isArray() && getComponentType().isAssignableFrom(other.getComponentType()));
|
||||
if (matchedBefore != null) {
|
||||
if (matchedBefore.get(this.type) == other.type) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// As of 6.1: shortcut assignability check for top-level Class references
|
||||
if (this.type instanceof Class<?> clazz && other.type instanceof Class<?> otherClazz) {
|
||||
return (strict ? clazz.isAssignableFrom(otherClazz) : ClassUtils.isAssignable(clazz, otherClazz));
|
||||
}
|
||||
}
|
||||
|
||||
if (matchedBefore != null && matchedBefore.get(this.type) == other.type) {
|
||||
return true;
|
||||
// Deal with array by delegating to the component type
|
||||
if (isArray()) {
|
||||
return (other.isArray() && getComponentType().isAssignableFrom(other.getComponentType(), true, matchedBefore));
|
||||
}
|
||||
|
||||
// Deal with wildcard bounds
|
||||
@@ -340,13 +350,15 @@ public class ResolvableType implements Serializable {
|
||||
}
|
||||
}
|
||||
if (ourResolved == null) {
|
||||
ourResolved = resolve(Object.class);
|
||||
ourResolved = toClass();
|
||||
}
|
||||
Class<?> otherResolved = other.toClass();
|
||||
|
||||
// We need an exact type match for generics
|
||||
// List<CharSequence> is not assignable from List<String>
|
||||
if (exactMatch ? !ourResolved.equals(otherResolved) : !ClassUtils.isAssignable(ourResolved, otherResolved)) {
|
||||
if (exactMatch ? !ourResolved.equals(otherResolved) :
|
||||
(strict ? !ourResolved.isAssignableFrom(otherResolved) :
|
||||
!ClassUtils.isAssignable(ourResolved, otherResolved))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -357,13 +369,15 @@ public class ResolvableType implements Serializable {
|
||||
if (ourGenerics.length != typeGenerics.length) {
|
||||
return false;
|
||||
}
|
||||
if (matchedBefore == null) {
|
||||
matchedBefore = new IdentityHashMap<>(1);
|
||||
}
|
||||
matchedBefore.put(this.type, other.type);
|
||||
for (int i = 0; i < ourGenerics.length; i++) {
|
||||
if (!ourGenerics[i].isAssignableFrom(typeGenerics[i], matchedBefore)) {
|
||||
return false;
|
||||
if (ourGenerics.length > 0) {
|
||||
if (matchedBefore == null) {
|
||||
matchedBefore = new IdentityHashMap<>(1);
|
||||
}
|
||||
matchedBefore.put(this.type, other.type);
|
||||
for (int i = 0; i < ourGenerics.length; i++) {
|
||||
if (!ourGenerics[i].isAssignableFrom(typeGenerics[i], true, matchedBefore)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user