Skip to content

Commit 7405e20

Browse files
committed
Merge branch '6.2.x'
# Conflicts: # spring-core/src/main/java/org/springframework/core/ResolvableType.java
2 parents 4620d86 + ed994dc commit 7405e20

File tree

4 files changed

+75
-26
lines changed

4 files changed

+75
-26
lines changed

spring-core/src/main/java/org/springframework/core/GenericTypeResolver.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ else if (genericType instanceof ParameterizedType parameterizedType) {
177177
generics[i] = resolvedTypeArgument;
178178
}
179179
else {
180-
generics[i] = ResolvableType.forType(typeArgument).resolveType();
180+
generics[i] = ResolvableType.forType(typeArgument);
181181
}
182182
}
183183
else if (typeArgument instanceof ParameterizedType) {
@@ -223,7 +223,7 @@ private static ResolvableType resolveVariable(TypeVariable<?> typeVariable, Reso
223223
return resolvedType;
224224
}
225225
}
226-
return ResolvableType.NONE;
226+
return ResolvableType.forVariableBounds(typeVariable);
227227
}
228228

229229
/**

spring-core/src/main/java/org/springframework/core/ResolvableType.java

+36-13
Original file line numberDiff line numberDiff line change
@@ -320,9 +320,6 @@ private boolean isAssignableFrom(ResolvableType other, boolean strict,
320320
other.getComponentType(), true, matchedBefore, upUntilUnresolvable));
321321
}
322322

323-
// We're checking nested generic variables now...
324-
boolean exactMatch = (strict && matchedBefore != null);
325-
326323
// Deal with wildcard bounds
327324
WildcardBounds ourBounds = WildcardBounds.get(this);
328325
WildcardBounds otherBounds = WildcardBounds.get(other);
@@ -336,8 +333,9 @@ private boolean isAssignableFrom(ResolvableType other, boolean strict,
336333
else if (upUntilUnresolvable) {
337334
return otherBounds.isAssignableFrom(this, matchedBefore);
338335
}
339-
else if (!exactMatch) {
340-
return otherBounds.isAssignableTo(this, matchedBefore);
336+
else if (!strict) {
337+
return (matchedBefore != null ? otherBounds.equalsType(this) :
338+
otherBounds.isAssignableTo(this, matchedBefore));
341339
}
342340
else {
343341
return false;
@@ -350,6 +348,7 @@ else if (!exactMatch) {
350348
}
351349

352350
// Main assignability check about to follow
351+
boolean exactMatch = (strict && matchedBefore != null);
353352
boolean checkGenerics = true;
354353
Class<?> ourResolved = null;
355354
if (this.type instanceof TypeVariable<?> variable) {
@@ -942,13 +941,6 @@ ResolvableType resolveType() {
942941
return NONE;
943942
}
944943

945-
private @Nullable Type resolveBounds(Type[] bounds) {
946-
if (bounds.length == 0 || bounds[0] == Object.class) {
947-
return null;
948-
}
949-
return bounds[0];
950-
}
951-
952944
private @Nullable ResolvableType resolveVariable(TypeVariable<?> variable) {
953945
if (this.type instanceof TypeVariable) {
954946
return resolveType().resolveVariable(variable);
@@ -1449,6 +1441,23 @@ public static ResolvableType forArrayComponent(ResolvableType componentType) {
14491441
return new ResolvableType(arrayType, componentType, null, null);
14501442
}
14511443

1444+
/**
1445+
* Return a {@code ResolvableType} for the bounds of the specified {@link TypeVariable}.
1446+
* @param typeVariable the type variable
1447+
* @return a {@code ResolvableType} for the specified bounds
1448+
* @since 6.2.3
1449+
*/
1450+
static ResolvableType forVariableBounds(TypeVariable<?> typeVariable) {
1451+
return forType(resolveBounds(typeVariable.getBounds()));
1452+
}
1453+
1454+
private static @Nullable Type resolveBounds(Type[] bounds) {
1455+
if (bounds.length == 0 || bounds[0] == Object.class) {
1456+
return null;
1457+
}
1458+
return bounds[0];
1459+
}
1460+
14521461
/**
14531462
* Return a {@code ResolvableType} for the specified {@link Type}.
14541463
* <p>Note: The resulting {@code ResolvableType} instance may not be {@link Serializable}.
@@ -1477,7 +1486,6 @@ public static ResolvableType forType(@Nullable Type type, @Nullable ResolvableTy
14771486
return forType(type, variableResolver);
14781487
}
14791488

1480-
14811489
/**
14821490
* Return a {@code ResolvableType} for the specified {@link ParameterizedTypeReference}.
14831491
* <p>Note: The resulting {@code ResolvableType} instance may not be {@link Serializable}.
@@ -1763,6 +1771,21 @@ public boolean isAssignableTo(ResolvableType type, @Nullable Map<Type, Type> mat
17631771
}
17641772
}
17651773

1774+
/**
1775+
* Return {@code true} if these bounds are equal to the specified type.
1776+
* @param type the type to test against
1777+
* @return {@code true} if these bounds are equal to the type
1778+
* @since 6.2.3
1779+
*/
1780+
public boolean equalsType(ResolvableType type) {
1781+
for (ResolvableType bound : this.bounds) {
1782+
if (!type.equalsType(bound)) {
1783+
return false;
1784+
}
1785+
}
1786+
return true;
1787+
}
1788+
17661789
/**
17671790
* Return the underlying bounds.
17681791
*/

spring-core/src/test/java/org/springframework/core/GenericTypeResolverTests.java

+28-11
Original file line numberDiff line numberDiff line change
@@ -212,19 +212,27 @@ void resolveNestedTypeVariable() throws Exception {
212212
}
213213

214214
@Test
215-
void resolvedTypeWithBase() {
216-
Type type = method(WithBaseTypes.class, "get").getGenericReturnType();
217-
Type resolvedType = resolveType(type, WithBaseTypes.class);
215+
void resolveTypeWithElementBounds() {
216+
Type type = method(WithElementBounds.class, "get").getGenericReturnType();
217+
Type resolvedType = resolveType(type, WithElementBounds.class);
218218
ParameterizedTypeReference<List<A>> reference = new ParameterizedTypeReference<>() {};
219219
assertThat(resolvedType).isEqualTo(reference.getType());
220220
}
221221

222+
@Test
223+
void resolveTypeWithUnresolvableElement() {
224+
Type type = method(WithUnresolvableElement.class, "get").getGenericReturnType();
225+
Type resolvedType = resolveType(type, WithUnresolvableElement.class);
226+
assertThat(resolvedType.toString()).isEqualTo("java.util.List<E>");
227+
}
228+
222229
private static Method method(Class<?> target, String methodName, Class<?>... parameterTypes) {
223230
Method method = findMethod(target, methodName, parameterTypes);
224231
assertThat(method).describedAs(target.getName() + "#" + methodName).isNotNull();
225232
return method;
226233
}
227234

235+
228236
public interface MyInterfaceType<T> {
229237
}
230238

@@ -348,33 +356,35 @@ public static class MySimpleTypeWithMethods extends MyTypeWithMethods<Integer> {
348356
static class GenericClass<T> {
349357
}
350358

351-
class A{}
359+
class A {}
352360

353-
class B<T>{}
361+
class B<T> {}
354362

355363
class C extends A {}
356364

357365
class D extends B<Long> {}
358366

359367
class E extends C {}
360368

361-
class TestIfc<T>{}
369+
class TestIfc<T> {}
362370

363-
class TestImpl<I extends A, T extends B<I>> extends TestIfc<T>{
371+
class TestImpl<I extends A, T extends B<I>> extends TestIfc<T> {
364372
}
365373

366374
abstract static class BiGenericClass<T extends B<?>, V extends A> {}
367375

368-
abstract static class SpecializedBiGenericClass<U extends C> extends BiGenericClass<D, U>{}
376+
abstract static class SpecializedBiGenericClass<U extends C> extends BiGenericClass<D, U> {}
369377

370378
static class TypeFixedBiGenericClass extends SpecializedBiGenericClass<E> {}
371379

372380
static class TopLevelClass<T> {
381+
373382
class Nested<X> {
374383
}
375384
}
376385

377386
static class TypedTopLevelClass extends TopLevelClass<Integer> {
387+
378388
class TypedNested extends Nested<Long> {
379389
}
380390
}
@@ -394,24 +404,31 @@ interface IdFixingRepository<T> extends Repository<T, Long> {
394404
}
395405

396406
static class WithMethodParameter {
407+
397408
public void nestedGenerics(List<Map<String, Integer>> input) {
398409
}
399410
}
400411

401-
public interface ListOfListSupplier<T> {
412+
interface ListOfListSupplier<T> {
402413

403414
List<List<T>> get();
404415
}
405416

406-
public interface StringListOfListSupplier extends ListOfListSupplier<String> {
417+
interface StringListOfListSupplier extends ListOfListSupplier<String> {
407418
}
408419

409-
static class WithBaseTypes {
420+
static class WithElementBounds {
410421

411422
<T extends A> List<T> get() {
412423
return List.of();
413424
}
425+
}
426+
427+
static class WithUnresolvableElement<T> {
414428

429+
List<T> get() {
430+
return List.of();
431+
}
415432
}
416433

417434
}

spring-core/src/test/java/org/springframework/core/ResolvableTypeTests.java

+9
Original file line numberDiff line numberDiff line change
@@ -1230,6 +1230,8 @@ void strictGenericsMatching() {
12301230
ResolvableType consumerUnresolved = ResolvableType.forClass(Consumer.class);
12311231
ResolvableType consumerObject = ResolvableType.forClassWithGenerics(Consumer.class, Object.class);
12321232
ResolvableType consumerNestedUnresolved = ResolvableType.forClassWithGenerics(Consumer.class, ResolvableType.forClass(Consumer.class));
1233+
ResolvableType consumerNumber = ResolvableType.forClassWithGenerics(Consumer.class, Number.class);
1234+
ResolvableType consumerExtendsNumber = ResolvableType.forClass(SubConsumer.class);
12331235

12341236
assertThat(consumerUnresolved.isAssignableFrom(consumerObject)).isTrue();
12351237
assertThat(consumerUnresolved.isAssignableFromResolvedPart(consumerObject)).isTrue();
@@ -1239,6 +1241,10 @@ void strictGenericsMatching() {
12391241
assertThat(consumerUnresolved.isAssignableFromResolvedPart(consumerNestedUnresolved)).isTrue();
12401242
assertThat(consumerObject.isAssignableFrom(consumerNestedUnresolved)).isFalse();
12411243
assertThat(consumerObject.isAssignableFromResolvedPart(consumerNestedUnresolved)).isFalse();
1244+
assertThat(consumerObject.isAssignableFrom(consumerNumber)).isFalse();
1245+
assertThat(consumerObject.isAssignableFromResolvedPart(consumerNumber)).isFalse();
1246+
assertThat(consumerObject.isAssignableFrom(consumerExtendsNumber)).isFalse();
1247+
assertThat(consumerObject.isAssignableFromResolvedPart(consumerExtendsNumber)).isTrue();
12421248
}
12431249

12441250
@Test
@@ -1788,6 +1794,9 @@ public class MyCollectionSuperclassType extends MySuperclassType<Collection<Stri
17881794
public interface Consumer<T> {
17891795
}
17901796

1797+
private static class SubConsumer<N extends Number> implements Consumer<N> {
1798+
}
1799+
17911800
public class Wildcard<T extends CharSequence> {
17921801
}
17931802

0 commit comments

Comments
 (0)