Skip to content

Commit 60bfead

Browse files
committedNov 30, 2023
Improve GenericTypeResolver to resolve type variable recursively
Fix GH-24963
1 parent dc5bef1 commit 60bfead

File tree

5 files changed

+45
-8
lines changed

5 files changed

+45
-8
lines changed
 

‎spring-context/src/main/java/org/springframework/context/event/ApplicationListenerMethodAdapter.java

+5-3
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
* @author Juergen Hoeller
6868
* @author Sam Brannen
6969
* @author Sebastien Deleuze
70+
* @author Yanming Zhou
7071
* @since 4.2
7172
*/
7273
public class ApplicationListenerMethodAdapter implements GenericApplicationListener {
@@ -177,13 +178,14 @@ public boolean supportsEventType(ResolvableType eventType) {
177178
return true;
178179
}
179180
if (PayloadApplicationEvent.class.isAssignableFrom(eventType.toClass())) {
180-
if (eventType.hasUnresolvableGenerics()) {
181-
return true;
182-
}
183181
ResolvableType payloadType = eventType.as(PayloadApplicationEvent.class).getGeneric();
184182
if (declaredEventType.isAssignableFrom(payloadType)) {
185183
return true;
186184
}
185+
if (payloadType.resolve() == null) {
186+
// Always accept such event when the type is erased
187+
return true;
188+
}
187189
}
188190
}
189191
return false;

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

+8-4
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
* @author Rob Harrop
4040
* @author Sam Brannen
4141
* @author Phillip Webb
42+
* @author Yanming Zhou
4243
* @since 2.5.2
4344
*/
4445
public final class GenericTypeResolver {
@@ -167,22 +168,25 @@ public static Type resolveType(Type genericType, @Nullable Class<?> contextClass
167168
else if (genericType instanceof ParameterizedType parameterizedType) {
168169
ResolvableType resolvedType = ResolvableType.forType(genericType);
169170
if (resolvedType.hasUnresolvableGenerics()) {
170-
Class<?>[] generics = new Class<?>[parameterizedType.getActualTypeArguments().length];
171+
ResolvableType[] generics = new ResolvableType[parameterizedType.getActualTypeArguments().length];
171172
Type[] typeArguments = parameterizedType.getActualTypeArguments();
172173
ResolvableType contextType = ResolvableType.forClass(contextClass);
173174
for (int i = 0; i < typeArguments.length; i++) {
174175
Type typeArgument = typeArguments[i];
175176
if (typeArgument instanceof TypeVariable<?> typeVariable) {
176177
ResolvableType resolvedTypeArgument = resolveVariable(typeVariable, contextType);
177178
if (resolvedTypeArgument != ResolvableType.NONE) {
178-
generics[i] = resolvedTypeArgument.resolve();
179+
generics[i] = resolvedTypeArgument;
179180
}
180181
else {
181-
generics[i] = ResolvableType.forType(typeArgument).resolve();
182+
generics[i] = ResolvableType.forType(typeArgument);
182183
}
183184
}
185+
else if (typeArgument instanceof ParameterizedType) {
186+
generics[i] = ResolvableType.forType(resolveType(typeArgument, contextClass));
187+
}
184188
else {
185-
generics[i] = ResolvableType.forType(typeArgument).resolve();
189+
generics[i] = ResolvableType.forType(typeArgument);
186190
}
187191
}
188192
Class<?> rawClass = resolvedType.getRawClass();

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
* @author Phillip Webb
7171
* @author Juergen Hoeller
7272
* @author Stephane Nicoll
73+
* @author Yanming Zhou
7374
* @since 4.0
7475
* @see #forField(Field)
7576
* @see #forMethodParameter(Method, int)
@@ -572,7 +573,7 @@ public boolean hasUnresolvableGenerics() {
572573
private boolean determineUnresolvableGenerics() {
573574
ResolvableType[] generics = getGenerics();
574575
for (ResolvableType generic : generics) {
575-
if (generic.isUnresolvableTypeVariable() || generic.isWildcardWithoutBounds()) {
576+
if (generic.isUnresolvableTypeVariable() || generic.isWildcardWithoutBounds() || generic.hasUnresolvableGenerics()) {
576577
return true;
577578
}
578579
}

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

+17
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
* @author Sam Brannen
4040
* @author Sebastien Deleuze
4141
* @author Stephane Nicoll
42+
* @author Yanming Zhou
4243
*/
4344
@SuppressWarnings({"unchecked", "rawtypes"})
4445
class GenericTypeResolverTests {
@@ -203,6 +204,13 @@ public void resolveMethodParameterWithNestedGenerics() {
203204
assertThat(resolvedType).isEqualTo(reference.getType());
204205
}
205206

207+
@Test
208+
void resolveNestedTypeVariable() throws Exception {
209+
Type resolved = resolveType(ListOfListSupplier.class.getMethod("get").getGenericReturnType(),
210+
StringListOfListSupplier.class);
211+
assertThat(ResolvableType.forType(resolved).getGeneric(0).getGeneric(0).resolve()).isEqualTo(String.class);
212+
}
213+
206214
private static Method method(Class<?> target, String methodName, Class<?>... parameterTypes) {
207215
Method method = findMethod(target, methodName, parameterTypes);
208216
assertThat(method).describedAs(target.getName() + "#" + methodName).isNotNull();
@@ -402,5 +410,14 @@ public void nestedGenerics(List<Map<String, Integer>> input) {
402410
}
403411
}
404412

413+
public interface ListOfListSupplier<T> {
414+
415+
List<List<T>> get();
416+
417+
}
418+
419+
public interface StringListOfListSupplier extends ListOfListSupplier<String> {
420+
421+
}
405422

406423
}

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

+13
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
* @author Phillip Webb
6767
* @author Juergen Hoeller
6868
* @author Sebastien Deleuze
69+
* @author Yanming Zhou
6970
*/
7071
@SuppressWarnings("rawtypes")
7172
@ExtendWith(MockitoExtension.class)
@@ -1314,6 +1315,12 @@ void hasUnresolvableGenericsWhenExtends() throws Exception {
13141315
assertThat(type.hasUnresolvableGenerics()).isTrue();
13151316
}
13161317

1318+
@Test
1319+
void hasUnresolvableGenericsWhenNested() throws Exception {
1320+
ResolvableType type = ResolvableType.forMethodReturnType(ListOfListSupplier.class.getMethod("get"));
1321+
assertThat(type.hasUnresolvableGenerics()).isTrue();
1322+
}
1323+
13171324
@Test
13181325
void spr11219() throws Exception {
13191326
ResolvableType type = ResolvableType.forField(BaseProvider.class.getField("stuff"), BaseProvider.class);
@@ -1617,6 +1624,12 @@ interface ListOfGenericArray extends List<List<String>[]> {
16171624
}
16181625

16191626

1627+
public interface ListOfListSupplier<T> {
1628+
1629+
List<List<T>> get();
1630+
1631+
}
1632+
16201633
static class EnclosedInParameterizedType<T> {
16211634

16221635
static class InnerRaw {

0 commit comments

Comments
 (0)