diff --git a/spring-context/src/main/java/org/springframework/context/event/ApplicationListenerMethodAdapter.java b/spring-context/src/main/java/org/springframework/context/event/ApplicationListenerMethodAdapter.java index d60615b7af..e3446c83d1 100644 --- a/spring-context/src/main/java/org/springframework/context/event/ApplicationListenerMethodAdapter.java +++ b/spring-context/src/main/java/org/springframework/context/event/ApplicationListenerMethodAdapter.java @@ -67,6 +67,7 @@ import org.springframework.util.StringUtils; * @author Juergen Hoeller * @author Sam Brannen * @author Sebastien Deleuze + * @author Yanming Zhou * @since 4.2 */ public class ApplicationListenerMethodAdapter implements GenericApplicationListener { @@ -177,13 +178,14 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe return true; } if (PayloadApplicationEvent.class.isAssignableFrom(eventType.toClass())) { - if (eventType.hasUnresolvableGenerics()) { - return true; - } ResolvableType payloadType = eventType.as(PayloadApplicationEvent.class).getGeneric(); if (declaredEventType.isAssignableFrom(payloadType)) { return true; } + if (payloadType.resolve() == null) { + // Always accept such event when the type is erased + return true; + } } } return false; diff --git a/spring-core/src/main/java/org/springframework/core/GenericTypeResolver.java b/spring-core/src/main/java/org/springframework/core/GenericTypeResolver.java index d08be27dcb..4e4e1225ab 100644 --- a/spring-core/src/main/java/org/springframework/core/GenericTypeResolver.java +++ b/spring-core/src/main/java/org/springframework/core/GenericTypeResolver.java @@ -39,6 +39,7 @@ import org.springframework.util.ConcurrentReferenceHashMap; * @author Rob Harrop * @author Sam Brannen * @author Phillip Webb + * @author Yanming Zhou * @since 2.5.2 */ public final class GenericTypeResolver { @@ -167,7 +168,7 @@ public final class GenericTypeResolver { else if (genericType instanceof ParameterizedType parameterizedType) { ResolvableType resolvedType = ResolvableType.forType(genericType); if (resolvedType.hasUnresolvableGenerics()) { - Class[] generics = new Class[parameterizedType.getActualTypeArguments().length]; + ResolvableType[] generics = new ResolvableType[parameterizedType.getActualTypeArguments().length]; Type[] typeArguments = parameterizedType.getActualTypeArguments(); ResolvableType contextType = ResolvableType.forClass(contextClass); for (int i = 0; i < typeArguments.length; i++) { @@ -175,14 +176,17 @@ public final class GenericTypeResolver { if (typeArgument instanceof TypeVariable typeVariable) { ResolvableType resolvedTypeArgument = resolveVariable(typeVariable, contextType); if (resolvedTypeArgument != ResolvableType.NONE) { - generics[i] = resolvedTypeArgument.resolve(); + generics[i] = resolvedTypeArgument; } else { - generics[i] = ResolvableType.forType(typeArgument).resolve(); + generics[i] = ResolvableType.forType(typeArgument); } } + else if (typeArgument instanceof ParameterizedType) { + generics[i] = ResolvableType.forType(resolveType(typeArgument, contextClass)); + } else { - generics[i] = ResolvableType.forType(typeArgument).resolve(); + generics[i] = ResolvableType.forType(typeArgument); } } Class rawClass = resolvedType.getRawClass(); diff --git a/spring-core/src/main/java/org/springframework/core/ResolvableType.java b/spring-core/src/main/java/org/springframework/core/ResolvableType.java index 510b191c9a..fc70a6c9eb 100644 --- a/spring-core/src/main/java/org/springframework/core/ResolvableType.java +++ b/spring-core/src/main/java/org/springframework/core/ResolvableType.java @@ -70,6 +70,7 @@ import org.springframework.util.StringUtils; * @author Phillip Webb * @author Juergen Hoeller * @author Stephane Nicoll + * @author Yanming Zhou * @since 4.0 * @see #forField(Field) * @see #forMethodParameter(Method, int) @@ -572,7 +573,7 @@ public class ResolvableType implements Serializable { private boolean determineUnresolvableGenerics() { ResolvableType[] generics = getGenerics(); for (ResolvableType generic : generics) { - if (generic.isUnresolvableTypeVariable() || generic.isWildcardWithoutBounds()) { + if (generic.isUnresolvableTypeVariable() || generic.isWildcardWithoutBounds() || generic.hasUnresolvableGenerics()) { return true; } } diff --git a/spring-core/src/test/java/org/springframework/core/GenericTypeResolverTests.java b/spring-core/src/test/java/org/springframework/core/GenericTypeResolverTests.java index 3290133fd2..7d519cf305 100644 --- a/spring-core/src/test/java/org/springframework/core/GenericTypeResolverTests.java +++ b/spring-core/src/test/java/org/springframework/core/GenericTypeResolverTests.java @@ -39,6 +39,7 @@ import static org.springframework.util.ReflectionUtils.findMethod; * @author Sam Brannen * @author Sebastien Deleuze * @author Stephane Nicoll + * @author Yanming Zhou */ @SuppressWarnings({"unchecked", "rawtypes"}) class GenericTypeResolverTests { @@ -203,6 +204,13 @@ class GenericTypeResolverTests { assertThat(resolvedType).isEqualTo(reference.getType()); } + @Test + void resolveNestedTypeVariable() throws Exception { + Type resolved = resolveType(ListOfListSupplier.class.getMethod("get").getGenericReturnType(), + StringListOfListSupplier.class); + assertThat(ResolvableType.forType(resolved).getGeneric(0).getGeneric(0).resolve()).isEqualTo(String.class); + } + private static Method method(Class target, String methodName, Class... parameterTypes) { Method method = findMethod(target, methodName, parameterTypes); assertThat(method).describedAs(target.getName() + "#" + methodName).isNotNull(); @@ -382,5 +390,14 @@ class GenericTypeResolverTests { } } + public interface ListOfListSupplier { + + List> get(); + + } + + public interface StringListOfListSupplier extends ListOfListSupplier { + + } } diff --git a/spring-core/src/test/java/org/springframework/core/ResolvableTypeTests.java b/spring-core/src/test/java/org/springframework/core/ResolvableTypeTests.java index 7880ca35d3..64c0ee5ee4 100644 --- a/spring-core/src/test/java/org/springframework/core/ResolvableTypeTests.java +++ b/spring-core/src/test/java/org/springframework/core/ResolvableTypeTests.java @@ -66,6 +66,7 @@ import static org.mockito.Mockito.verify; * @author Phillip Webb * @author Juergen Hoeller * @author Sebastien Deleuze + * @author Yanming Zhou */ @SuppressWarnings("rawtypes") @ExtendWith(MockitoExtension.class) @@ -1314,6 +1315,12 @@ class ResolvableTypeTests { assertThat(type.hasUnresolvableGenerics()).isTrue(); } + @Test + void hasUnresolvableGenericsWhenNested() throws Exception { + ResolvableType type = ResolvableType.forMethodReturnType(ListOfListSupplier.class.getMethod("get")); + assertThat(type.hasUnresolvableGenerics()).isTrue(); + } + @Test void spr11219() throws Exception { ResolvableType type = ResolvableType.forField(BaseProvider.class.getField("stuff"), BaseProvider.class); @@ -1617,6 +1624,12 @@ class ResolvableTypeTests { } + public interface ListOfListSupplier { + + List> get(); + + } + static class EnclosedInParameterizedType { static class InnerRaw {