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 f612104557..612d2752f5 100644 --- a/spring-context/src/main/java/org/springframework/context/PayloadApplicationEvent.java +++ b/spring-context/src/main/java/org/springframework/context/PayloadApplicationEvent.java @@ -39,17 +39,7 @@ public class PayloadApplicationEvent extends ApplicationEvent implements Reso private final T payload; - @Nullable - private ResolvableType payloadType; - - /** - * 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}) - */ - public PayloadApplicationEvent(Object source, T payload) { - this(source, payload, null); - } + private final ResolvableType payloadType; /** * Create a new PayloadApplicationEvent. @@ -61,15 +51,21 @@ public class PayloadApplicationEvent extends ApplicationEvent implements Reso super(source); Assert.notNull(payload, "Payload must not be null"); this.payload = payload; - this.payloadType = payloadType; + this.payloadType = (payloadType != null) ? payloadType : ResolvableType.forInstance(payload); + } + + /** + * Create a new PayloadApplicationEvent, using the instance to infer its type. + * @param source the object on which the event initially occurred (never {@code null}) + * @param payload the payload object (never {@code null}) + */ + public PayloadApplicationEvent(Object source, T payload) { + this(source, payload, null); } @Override public ResolvableType getResolvableType() { - if (this.payloadType == null) { - this.payloadType = ResolvableType.forInstance(getPayload()); - } return ResolvableType.forClassWithGenerics(getClass(), this.payloadType); } 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 c95f163007..8c51dd2942 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,7 +60,6 @@ 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; @@ -623,17 +622,6 @@ 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() { @@ -1146,29 +1134,4 @@ 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 ++; - } - - - } - } diff --git a/spring-context/src/test/java/org/springframework/context/event/PayloadApplicationEventTests.java b/spring-context/src/test/java/org/springframework/context/event/PayloadApplicationEventTests.java index c752623bb5..8fb78ceda8 100644 --- a/spring-context/src/test/java/org/springframework/context/event/PayloadApplicationEventTests.java +++ b/spring-context/src/test/java/org/springframework/context/event/PayloadApplicationEventTests.java @@ -27,6 +27,7 @@ import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.PayloadApplicationEvent; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.support.GenericApplicationContext; +import org.springframework.core.ResolvableType; import org.springframework.stereotype.Component; import static org.assertj.core.api.Assertions.assertThat; @@ -34,10 +35,40 @@ import static org.assertj.core.api.Assertions.assertThat; /** * @author Juergen Hoeller */ -public class PayloadApplicationEventTests { +class PayloadApplicationEventTests { @Test - public void testEventClassWithInterface() { + void payloadApplicationEventWithNoTypeUsesInstance() { + NumberHolder payload = new NumberHolder<>(42); + PayloadApplicationEvent> event = new PayloadApplicationEvent<>(this, payload); + assertThat(event.getResolvableType()).satisfies(eventType -> { + assertThat(eventType.toClass()).isEqualTo(PayloadApplicationEvent.class); + assertThat(eventType.getGenerics()).hasSize(1); + assertThat(eventType.getGenerics()[0]).satisfies(bodyType -> { + assertThat(bodyType.toClass()).isEqualTo(NumberHolder.class); + assertThat(bodyType.hasUnresolvableGenerics()).isTrue(); + }); + }); + } + + @Test + void payloadApplicationEventWithType() { + NumberHolder payload = new NumberHolder<>(42); + ResolvableType payloadType = ResolvableType.forClassWithGenerics(NumberHolder.class, Integer.class); + PayloadApplicationEvent> event = new PayloadApplicationEvent<>(this, payload, payloadType); + assertThat(event.getResolvableType()).satisfies(eventType -> { + assertThat(eventType.toClass()).isEqualTo(PayloadApplicationEvent.class); + assertThat(eventType.getGenerics()).hasSize(1); + assertThat(eventType.getGenerics()[0]).satisfies(bodyType -> { + assertThat(bodyType.toClass()).isEqualTo(NumberHolder.class); + assertThat(bodyType.hasUnresolvableGenerics()).isFalse(); + assertThat(bodyType.getGenerics()[0].toClass()).isEqualTo(Integer.class); + }); + }); + } + + @Test + void testEventClassWithInterface() { ApplicationContext ac = new AnnotationConfigApplicationContext(AuditableListener.class); AuditablePayloadEvent event = new AuditablePayloadEvent<>(this, "xyz"); @@ -46,7 +77,7 @@ public class PayloadApplicationEventTests { } @Test - public void testProgrammaticEventListener() { + void testProgrammaticEventListener() { List events = new ArrayList<>(); ApplicationListener> listener = events::add; ApplicationListener> mismatch = (event -> event.getPayload().intValue()); @@ -62,7 +93,7 @@ public class PayloadApplicationEventTests { } @Test - public void testProgrammaticPayloadListener() { + void testProgrammaticPayloadListener() { List events = new ArrayList<>(); ApplicationListener> listener = ApplicationListener.forPayload(events::add); ApplicationListener> mismatch = ApplicationListener.forPayload(payload -> payload.intValue()); @@ -102,4 +133,14 @@ public class PayloadApplicationEventTests { } } + static class NumberHolder { + + private T number; + + public NumberHolder(T number) { + this.number = number; + } + + } + }