Support for matching partial generics

Closes gh-20727
This commit is contained in:
Juergen Hoeller
2024-02-15 16:51:09 +01:00
parent d4e8daaede
commit 7e67da8a26
3 changed files with 45 additions and 15 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 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.
@@ -265,7 +265,7 @@ public class ResolvableType implements Serializable {
public boolean isAssignableFrom(Class<?> other) {
// 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));
isAssignableFrom(forClass(other), false, null, false));
}
/**
@@ -280,10 +280,24 @@ public class ResolvableType implements Serializable {
* {@code ResolvableType}; {@code false} otherwise
*/
public boolean isAssignableFrom(ResolvableType other) {
return isAssignableFrom(other, false, null);
return isAssignableFrom(other, false, null, false);
}
private boolean isAssignableFrom(ResolvableType other, boolean strict, @Nullable Map<Type, Type> matchedBefore) {
/**
* Determine whether this {@code ResolvableType} is assignable from the
* specified other type, as far as the other type is actually resolvable.
* @param other the type to be checked against (as a {@code ResolvableType})
* @return {@code true} if the specified other type can be assigned to this
* {@code ResolvableType} as far as it is resolvable; {@code false} otherwise
* @since 6.2
*/
public boolean isAssignableFromResolvedPart(ResolvableType other) {
return isAssignableFrom(other, false, null, true);
}
private boolean isAssignableFrom(ResolvableType other, boolean strict,
@Nullable Map<Type, Type> matchedBefore, boolean upUntilUnresolvable) {
Assert.notNull(other, "ResolvableType must not be null");
// If we cannot resolve types, we are not assignable
@@ -305,7 +319,12 @@ public class ResolvableType implements Serializable {
// Deal with array by delegating to the component type
if (isArray()) {
return (other.isArray() && getComponentType().isAssignableFrom(other.getComponentType(), true, matchedBefore));
return (other.isArray() && getComponentType().isAssignableFrom(
other.getComponentType(), true, matchedBefore, upUntilUnresolvable));
}
if (upUntilUnresolvable && other.isUnresolvableTypeVariable()) {
return true;
}
// Deal with wildcard bounds
@@ -314,8 +333,15 @@ public class ResolvableType implements Serializable {
// In the form X is assignable to <? extends Number>
if (typeBounds != null) {
return (ourBounds != null && ourBounds.isSameKind(typeBounds) &&
ourBounds.isAssignableFrom(typeBounds.getBounds()));
if (ourBounds != null) {
return (ourBounds.isSameKind(typeBounds) && ourBounds.isAssignableFrom(typeBounds.getBounds()));
}
else if (upUntilUnresolvable) {
return typeBounds.isAssignableFrom(this);
}
else {
return false;
}
}
// In the form <? extends Number> is assignable to X...
@@ -376,7 +402,7 @@ 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)) {
if (!ourGenerics[i].isAssignableFrom(typeGenerics[i], true, matchedBefore, upUntilUnresolvable)) {
return false;
}
}