Merge branch '6.2.x'
# Conflicts: # spring-core/src/main/java/org/springframework/core/ResolvableType.java
This commit is contained in:
@@ -177,7 +177,7 @@ public final class GenericTypeResolver {
|
|||||||
generics[i] = resolvedTypeArgument;
|
generics[i] = resolvedTypeArgument;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
generics[i] = ResolvableType.forType(typeArgument).resolveType();
|
generics[i] = ResolvableType.forType(typeArgument);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (typeArgument instanceof ParameterizedType) {
|
else if (typeArgument instanceof ParameterizedType) {
|
||||||
@@ -223,7 +223,7 @@ public final class GenericTypeResolver {
|
|||||||
return resolvedType;
|
return resolvedType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ResolvableType.NONE;
|
return ResolvableType.forVariableBounds(typeVariable);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -320,9 +320,6 @@ public class ResolvableType implements Serializable {
|
|||||||
other.getComponentType(), true, matchedBefore, upUntilUnresolvable));
|
other.getComponentType(), true, matchedBefore, upUntilUnresolvable));
|
||||||
}
|
}
|
||||||
|
|
||||||
// We're checking nested generic variables now...
|
|
||||||
boolean exactMatch = (strict && matchedBefore != null);
|
|
||||||
|
|
||||||
// Deal with wildcard bounds
|
// Deal with wildcard bounds
|
||||||
WildcardBounds ourBounds = WildcardBounds.get(this);
|
WildcardBounds ourBounds = WildcardBounds.get(this);
|
||||||
WildcardBounds otherBounds = WildcardBounds.get(other);
|
WildcardBounds otherBounds = WildcardBounds.get(other);
|
||||||
@@ -336,8 +333,9 @@ public class ResolvableType implements Serializable {
|
|||||||
else if (upUntilUnresolvable) {
|
else if (upUntilUnresolvable) {
|
||||||
return otherBounds.isAssignableFrom(this, matchedBefore);
|
return otherBounds.isAssignableFrom(this, matchedBefore);
|
||||||
}
|
}
|
||||||
else if (!exactMatch) {
|
else if (!strict) {
|
||||||
return otherBounds.isAssignableTo(this, matchedBefore);
|
return (matchedBefore != null ? otherBounds.equalsType(this) :
|
||||||
|
otherBounds.isAssignableTo(this, matchedBefore));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return false;
|
return false;
|
||||||
@@ -350,6 +348,7 @@ public class ResolvableType implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Main assignability check about to follow
|
// Main assignability check about to follow
|
||||||
|
boolean exactMatch = (strict && matchedBefore != null);
|
||||||
boolean checkGenerics = true;
|
boolean checkGenerics = true;
|
||||||
Class<?> ourResolved = null;
|
Class<?> ourResolved = null;
|
||||||
if (this.type instanceof TypeVariable<?> variable) {
|
if (this.type instanceof TypeVariable<?> variable) {
|
||||||
@@ -942,13 +941,6 @@ public class ResolvableType implements Serializable {
|
|||||||
return NONE;
|
return NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
private @Nullable Type resolveBounds(Type[] bounds) {
|
|
||||||
if (bounds.length == 0 || bounds[0] == Object.class) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return bounds[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
private @Nullable ResolvableType resolveVariable(TypeVariable<?> variable) {
|
private @Nullable ResolvableType resolveVariable(TypeVariable<?> variable) {
|
||||||
if (this.type instanceof TypeVariable) {
|
if (this.type instanceof TypeVariable) {
|
||||||
return resolveType().resolveVariable(variable);
|
return resolveType().resolveVariable(variable);
|
||||||
@@ -1449,6 +1441,23 @@ public class ResolvableType implements Serializable {
|
|||||||
return new ResolvableType(arrayType, componentType, null, null);
|
return new ResolvableType(arrayType, componentType, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a {@code ResolvableType} for the bounds of the specified {@link TypeVariable}.
|
||||||
|
* @param typeVariable the type variable
|
||||||
|
* @return a {@code ResolvableType} for the specified bounds
|
||||||
|
* @since 6.2.3
|
||||||
|
*/
|
||||||
|
static ResolvableType forVariableBounds(TypeVariable<?> typeVariable) {
|
||||||
|
return forType(resolveBounds(typeVariable.getBounds()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static @Nullable Type resolveBounds(Type[] bounds) {
|
||||||
|
if (bounds.length == 0 || bounds[0] == Object.class) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return bounds[0];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a {@code ResolvableType} for the specified {@link Type}.
|
* Return a {@code ResolvableType} for the specified {@link Type}.
|
||||||
* <p>Note: The resulting {@code ResolvableType} instance may not be {@link Serializable}.
|
* <p>Note: The resulting {@code ResolvableType} instance may not be {@link Serializable}.
|
||||||
@@ -1477,7 +1486,6 @@ public class ResolvableType implements Serializable {
|
|||||||
return forType(type, variableResolver);
|
return forType(type, variableResolver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a {@code ResolvableType} for the specified {@link ParameterizedTypeReference}.
|
* Return a {@code ResolvableType} for the specified {@link ParameterizedTypeReference}.
|
||||||
* <p>Note: The resulting {@code ResolvableType} instance may not be {@link Serializable}.
|
* <p>Note: The resulting {@code ResolvableType} instance may not be {@link Serializable}.
|
||||||
@@ -1763,6 +1771,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.
|
* Return the underlying bounds.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -212,19 +212,27 @@ class GenericTypeResolverTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void resolvedTypeWithBase() {
|
void resolveTypeWithElementBounds() {
|
||||||
Type type = method(WithBaseTypes.class, "get").getGenericReturnType();
|
Type type = method(WithElementBounds.class, "get").getGenericReturnType();
|
||||||
Type resolvedType = resolveType(type, WithBaseTypes.class);
|
Type resolvedType = resolveType(type, WithElementBounds.class);
|
||||||
ParameterizedTypeReference<List<A>> reference = new ParameterizedTypeReference<>() {};
|
ParameterizedTypeReference<List<A>> reference = new ParameterizedTypeReference<>() {};
|
||||||
assertThat(resolvedType).isEqualTo(reference.getType());
|
assertThat(resolvedType).isEqualTo(reference.getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void resolveTypeWithUnresolvableElement() {
|
||||||
|
Type type = method(WithUnresolvableElement.class, "get").getGenericReturnType();
|
||||||
|
Type resolvedType = resolveType(type, WithUnresolvableElement.class);
|
||||||
|
assertThat(resolvedType.toString()).isEqualTo("java.util.List<E>");
|
||||||
|
}
|
||||||
|
|
||||||
private static Method method(Class<?> target, String methodName, Class<?>... parameterTypes) {
|
private static Method method(Class<?> target, String methodName, Class<?>... parameterTypes) {
|
||||||
Method method = findMethod(target, methodName, parameterTypes);
|
Method method = findMethod(target, methodName, parameterTypes);
|
||||||
assertThat(method).describedAs(target.getName() + "#" + methodName).isNotNull();
|
assertThat(method).describedAs(target.getName() + "#" + methodName).isNotNull();
|
||||||
return method;
|
return method;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public interface MyInterfaceType<T> {
|
public interface MyInterfaceType<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -348,9 +356,9 @@ class GenericTypeResolverTests {
|
|||||||
static class GenericClass<T> {
|
static class GenericClass<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
class A{}
|
class A {}
|
||||||
|
|
||||||
class B<T>{}
|
class B<T> {}
|
||||||
|
|
||||||
class C extends A {}
|
class C extends A {}
|
||||||
|
|
||||||
@@ -358,23 +366,25 @@ class GenericTypeResolverTests {
|
|||||||
|
|
||||||
class E extends C {}
|
class E extends C {}
|
||||||
|
|
||||||
class TestIfc<T>{}
|
class TestIfc<T> {}
|
||||||
|
|
||||||
class TestImpl<I extends A, T extends B<I>> extends TestIfc<T>{
|
class TestImpl<I extends A, T extends B<I>> extends TestIfc<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract static class BiGenericClass<T extends B<?>, V extends A> {}
|
abstract static class BiGenericClass<T extends B<?>, V extends A> {}
|
||||||
|
|
||||||
abstract static class SpecializedBiGenericClass<U extends C> extends BiGenericClass<D, U>{}
|
abstract static class SpecializedBiGenericClass<U extends C> extends BiGenericClass<D, U> {}
|
||||||
|
|
||||||
static class TypeFixedBiGenericClass extends SpecializedBiGenericClass<E> {}
|
static class TypeFixedBiGenericClass extends SpecializedBiGenericClass<E> {}
|
||||||
|
|
||||||
static class TopLevelClass<T> {
|
static class TopLevelClass<T> {
|
||||||
|
|
||||||
class Nested<X> {
|
class Nested<X> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static class TypedTopLevelClass extends TopLevelClass<Integer> {
|
static class TypedTopLevelClass extends TopLevelClass<Integer> {
|
||||||
|
|
||||||
class TypedNested extends Nested<Long> {
|
class TypedNested extends Nested<Long> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -394,24 +404,31 @@ class GenericTypeResolverTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static class WithMethodParameter {
|
static class WithMethodParameter {
|
||||||
|
|
||||||
public void nestedGenerics(List<Map<String, Integer>> input) {
|
public void nestedGenerics(List<Map<String, Integer>> input) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface ListOfListSupplier<T> {
|
interface ListOfListSupplier<T> {
|
||||||
|
|
||||||
List<List<T>> get();
|
List<List<T>> get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface StringListOfListSupplier extends ListOfListSupplier<String> {
|
interface StringListOfListSupplier extends ListOfListSupplier<String> {
|
||||||
}
|
}
|
||||||
|
|
||||||
static class WithBaseTypes {
|
static class WithElementBounds {
|
||||||
|
|
||||||
<T extends A> List<T> get() {
|
<T extends A> List<T> get() {
|
||||||
return List.of();
|
return List.of();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class WithUnresolvableElement<T> {
|
||||||
|
|
||||||
|
List<T> get() {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1230,6 +1230,8 @@ class ResolvableTypeTests {
|
|||||||
ResolvableType consumerUnresolved = ResolvableType.forClass(Consumer.class);
|
ResolvableType consumerUnresolved = ResolvableType.forClass(Consumer.class);
|
||||||
ResolvableType consumerObject = ResolvableType.forClassWithGenerics(Consumer.class, Object.class);
|
ResolvableType consumerObject = ResolvableType.forClassWithGenerics(Consumer.class, Object.class);
|
||||||
ResolvableType consumerNestedUnresolved = ResolvableType.forClassWithGenerics(Consumer.class, ResolvableType.forClass(Consumer.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.isAssignableFrom(consumerObject)).isTrue();
|
||||||
assertThat(consumerUnresolved.isAssignableFromResolvedPart(consumerObject)).isTrue();
|
assertThat(consumerUnresolved.isAssignableFromResolvedPart(consumerObject)).isTrue();
|
||||||
@@ -1239,6 +1241,10 @@ class ResolvableTypeTests {
|
|||||||
assertThat(consumerUnresolved.isAssignableFromResolvedPart(consumerNestedUnresolved)).isTrue();
|
assertThat(consumerUnresolved.isAssignableFromResolvedPart(consumerNestedUnresolved)).isTrue();
|
||||||
assertThat(consumerObject.isAssignableFrom(consumerNestedUnresolved)).isFalse();
|
assertThat(consumerObject.isAssignableFrom(consumerNestedUnresolved)).isFalse();
|
||||||
assertThat(consumerObject.isAssignableFromResolvedPart(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
|
@Test
|
||||||
@@ -1788,6 +1794,9 @@ class ResolvableTypeTests {
|
|||||||
public interface Consumer<T> {
|
public interface Consumer<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class SubConsumer<N extends Number> implements Consumer<N> {
|
||||||
|
}
|
||||||
|
|
||||||
public class Wildcard<T extends CharSequence> {
|
public class Wildcard<T extends CharSequence> {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user