Support for Collection-based return type
If an `@EventListener` annotated method returns a Collection or an Array, each individual items are now published as an event instead of publishing one event with said collection. Issue: SPR-12733
This commit is contained in:
parent
7191050e26
commit
152a7b645f
|
|
@ -19,8 +19,8 @@ package org.springframework.context.event;
|
|||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Parameter;
|
||||
import java.lang.reflect.UndeclaredThrowableException;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
|
@ -37,6 +37,7 @@ import org.springframework.core.annotation.AnnotationUtils;
|
|||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
|
|
@ -136,7 +137,27 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
|
|||
|
||||
protected void handleResult(Object result) {
|
||||
Assert.notNull(this.applicationContext, "ApplicationContext must no be null.");
|
||||
this.applicationContext.publishEvent(result);
|
||||
if (result.getClass().isArray()) {
|
||||
Object[] events = ObjectUtils.toObjectArray(result);
|
||||
for (Object event : events) {
|
||||
publishEvent(event);
|
||||
}
|
||||
}
|
||||
else if (result instanceof Collection<?>) {
|
||||
Collection<?> events = (Collection<?>) result;
|
||||
for (Object event : events) {
|
||||
publishEvent(event);
|
||||
}
|
||||
}
|
||||
else {
|
||||
publishEvent(result);
|
||||
}
|
||||
}
|
||||
|
||||
private void publishEvent(Object event) {
|
||||
if (event != null) {
|
||||
this.applicationContext.publishEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,9 @@ import java.lang.annotation.RetentionPolicy;
|
|||
import java.lang.annotation.Target;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
|
@ -157,7 +159,7 @@ public class AnnotationDrivenEventListenerTests {
|
|||
this.eventCollector.assertNoEventReceived(replyEventListener);
|
||||
this.context.publishEvent(event);
|
||||
this.eventCollector.assertEvent(replyEventListener, event);
|
||||
this.eventCollector.assertEvent(listener, new TestEvent(replyEventListener, event.getId(), event.msg)); // reply
|
||||
this.eventCollector.assertEvent(listener, new TestEvent(replyEventListener, event.getId(), "dummy")); // reply
|
||||
this.eventCollector.assertTotalEventsCount(2);
|
||||
}
|
||||
|
||||
|
|
@ -176,6 +178,55 @@ public class AnnotationDrivenEventListenerTests {
|
|||
this.eventCollector.assertTotalEventsCount(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void arrayReply() {
|
||||
load(TestEventListener.class, ReplyEventListener.class);
|
||||
AnotherTestEvent event = new AnotherTestEvent(this, new String[]{"first", "second"});
|
||||
ReplyEventListener replyEventListener = this.context.getBean(ReplyEventListener.class);
|
||||
TestEventListener listener = this.context.getBean(TestEventListener.class);
|
||||
|
||||
this.eventCollector.assertNoEventReceived(listener);
|
||||
this.eventCollector.assertNoEventReceived(replyEventListener);
|
||||
this.context.publishEvent(event);
|
||||
this.eventCollector.assertEvent(replyEventListener, event);
|
||||
this.eventCollector.assertEvent(listener, "first", "second"); // reply
|
||||
this.eventCollector.assertTotalEventsCount(3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void collectionReply() {
|
||||
load(TestEventListener.class, ReplyEventListener.class);
|
||||
Set<Object> replies = new LinkedHashSet<>();
|
||||
replies.add("first");
|
||||
replies.add(4L);
|
||||
replies.add("third");
|
||||
AnotherTestEvent event = new AnotherTestEvent(this, replies);
|
||||
ReplyEventListener replyEventListener = this.context.getBean(ReplyEventListener.class);
|
||||
TestEventListener listener = this.context.getBean(TestEventListener.class);
|
||||
|
||||
this.eventCollector.assertNoEventReceived(listener);
|
||||
this.eventCollector.assertNoEventReceived(replyEventListener);
|
||||
this.context.publishEvent(event);
|
||||
this.eventCollector.assertEvent(replyEventListener, event);
|
||||
this.eventCollector.assertEvent(listener, "first", "third"); // reply (no listener for 4L)
|
||||
this.eventCollector.assertTotalEventsCount(3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void collectionReplyNullValue() {
|
||||
load(TestEventListener.class, ReplyEventListener.class);
|
||||
AnotherTestEvent event = new AnotherTestEvent(this, Arrays.asList(null, "test"));
|
||||
ReplyEventListener replyEventListener = this.context.getBean(ReplyEventListener.class);
|
||||
TestEventListener listener = this.context.getBean(TestEventListener.class);
|
||||
|
||||
this.eventCollector.assertNoEventReceived(listener);
|
||||
this.eventCollector.assertNoEventReceived(replyEventListener);
|
||||
this.context.publishEvent(event);
|
||||
this.eventCollector.assertEvent(replyEventListener, event);
|
||||
this.eventCollector.assertEvent(listener, "test");
|
||||
this.eventCollector.assertTotalEventsCount(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void eventListenerWorksWithInterfaceProxy() throws Exception {
|
||||
load(ProxyTestBean.class);
|
||||
|
|
@ -464,15 +515,19 @@ public class AnnotationDrivenEventListenerTests {
|
|||
@EventListener
|
||||
public Object handle(AnotherTestEvent event) {
|
||||
collectEvent(event);
|
||||
if (event.msg == null) {
|
||||
if (event.content == null) {
|
||||
return null;
|
||||
}
|
||||
else if (event.msg.equals("String")) {
|
||||
return event.msg;
|
||||
}
|
||||
else {
|
||||
return new TestEvent(this, event.getId(), event.msg);
|
||||
else if (event.content instanceof String) {
|
||||
String s = (String) event.content;
|
||||
if (s.equals("String")) {
|
||||
return event.content;
|
||||
}
|
||||
else {
|
||||
return new TestEvent(this, event.getId(), s);
|
||||
}
|
||||
}
|
||||
return event.content;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -495,7 +550,7 @@ public class AnnotationDrivenEventListenerTests {
|
|||
@Async
|
||||
public void handleAsync(AnotherTestEvent event) {
|
||||
collectEvent(event);
|
||||
if ("fail".equals(event.msg)) {
|
||||
if ("fail".equals(event.content)) {
|
||||
countDownLatch.countDown();
|
||||
throw new IllegalStateException("Test exception");
|
||||
}
|
||||
|
|
@ -517,7 +572,7 @@ public class AnnotationDrivenEventListenerTests {
|
|||
@EventListener
|
||||
@Async
|
||||
public void handleAsync(AnotherTestEvent event) {
|
||||
assertTrue(!Thread.currentThread().getName().equals(event.msg));
|
||||
assertTrue(!Thread.currentThread().getName().equals(event.content));
|
||||
collectEvent(event);
|
||||
countDownLatch.countDown();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,11 +22,11 @@ package org.springframework.context.event.test;
|
|||
@SuppressWarnings("serial")
|
||||
public class AnotherTestEvent extends IdentifiableApplicationEvent {
|
||||
|
||||
public final String msg;
|
||||
public final Object content;
|
||||
|
||||
public AnotherTestEvent(Object source, String msg) {
|
||||
public AnotherTestEvent(Object source, Object content) {
|
||||
super(source);
|
||||
this.msg = msg;
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue