From 6283456ef24c4271469ea67ff21b95e303d708c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=85=B6=E8=8B=97?= Date: Wed, 26 Feb 2020 18:57:35 +0800 Subject: [PATCH] Add support for explicit generic type in PayloadApplicationEvent See gh-24599 --- .../context/PayloadApplicationEvent.java | 20 +++++++++- .../support/AbstractApplicationContext.java | 2 +- .../AnnotationDrivenEventListenerTests.java | 37 +++++++++++++++++++ 3 files changed, 57 insertions(+), 2 deletions(-) diff --git a/spring-context/src/main/java/org/springframework/context/PayloadApplicationEvent.java b/spring-context/src/main/java/org/springframework/context/PayloadApplicationEvent.java index addcbc5dd97..f6121045576 100644 --- a/spring-context/src/main/java/org/springframework/context/PayloadApplicationEvent.java +++ b/spring-context/src/main/java/org/springframework/context/PayloadApplicationEvent.java @@ -20,6 +20,7 @@ import java.util.function.Consumer; import org.springframework.core.ResolvableType; import org.springframework.core.ResolvableTypeProvider; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -27,6 +28,7 @@ import org.springframework.util.Assert; * * @author Stephane Nicoll * @author Juergen Hoeller + * @author Qimiao Chen * @since 4.2 * @param the payload type of the event * @see ApplicationEventPublisher#publishEvent(Object) @@ -37,6 +39,8 @@ public class PayloadApplicationEvent extends ApplicationEvent implements Reso private final T payload; + @Nullable + private ResolvableType payloadType; /** * Create a new PayloadApplicationEvent. @@ -44,15 +48,29 @@ public class PayloadApplicationEvent extends ApplicationEvent implements Reso * @param payload the payload object (never {@code null}) */ public PayloadApplicationEvent(Object source, T payload) { + this(source, payload, null); + } + + /** + * Create a new PayloadApplicationEvent. + * @param source the object on which the event initially occurred (never {@code null}) + * @param payload the payload object (never {@code null}) + * @param payloadType the type object of payload object (can be {@code null}) + */ + public PayloadApplicationEvent(Object source, T payload, @Nullable ResolvableType payloadType) { super(source); Assert.notNull(payload, "Payload must not be null"); this.payload = payload; + this.payloadType = payloadType; } @Override public ResolvableType getResolvableType() { - return ResolvableType.forClassWithGenerics(getClass(), ResolvableType.forInstance(getPayload())); + if (this.payloadType == null) { + this.payloadType = ResolvableType.forInstance(getPayload()); + } + return ResolvableType.forClassWithGenerics(getClass(), this.payloadType); } /** diff --git a/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java b/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java index 27b050838cd..1bb789a46e9 100644 --- a/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java +++ b/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java @@ -407,7 +407,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader applicationEvent = (ApplicationEvent) event; } else { - applicationEvent = new PayloadApplicationEvent<>(this, event); + applicationEvent = new PayloadApplicationEvent<>(this, event, eventType); if (eventType == null) { eventType = ((PayloadApplicationEvent) applicationEvent).getResolvableType(); } diff --git a/spring-context/src/test/java/org/springframework/context/event/AnnotationDrivenEventListenerTests.java b/spring-context/src/test/java/org/springframework/context/event/AnnotationDrivenEventListenerTests.java index 8c51dd29420..c95f163007c 100644 --- a/spring-context/src/test/java/org/springframework/context/event/AnnotationDrivenEventListenerTests.java +++ b/spring-context/src/test/java/org/springframework/context/event/AnnotationDrivenEventListenerTests.java @@ -60,6 +60,7 @@ import org.springframework.context.event.test.GenericEventPojo; import org.springframework.context.event.test.Identifiable; import org.springframework.context.event.test.TestEvent; import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.core.ResolvableType; import org.springframework.core.annotation.AliasFor; import org.springframework.core.annotation.Order; import org.springframework.scheduling.annotation.Async; @@ -622,6 +623,17 @@ class AnnotationDrivenEventListenerTests { this.eventCollector.assertNoEventReceived(listener); this.eventCollector.assertTotalEventsCount(0); } + @Test + public void publishEventWithGeneric() throws NoSuchMethodException { + MyAnnotationConfigApplicationContext ctx = new MyAnnotationConfigApplicationContext(); + context = ctx; + ctx.register(MyEventWithGenericListener.class); + ctx.refresh(); + ResolvableType resolvableType = ResolvableType.forMethodParameter(MyEventWithGenericListener.class.getMethod("onMyEventWithGeneric",MyEventWithGeneric.class),0); + ctx.publishEvent(new MyEventWithGeneric(),resolvableType); + assertThat(MyEventWithGenericListener.count).isEqualTo(1); + } + @Test void orderedListeners() { @@ -1134,4 +1146,29 @@ class AnnotationDrivenEventListenerTests { } } + public static class MyAnnotationConfigApplicationContext extends AnnotationConfigApplicationContext{ + + @Override + public void publishEvent(Object event, ResolvableType eventType) { + super.publishEvent(event, eventType); + } + } + + public static class MyEventWithGeneric { + + } + + @Component + public static class MyEventWithGenericListener{ + + public static int count ; + + @EventListener + public void onMyEventWithGeneric(MyEventWithGeneric event){ + count ++; + } + + + } + }