Skip to content

Commit f948742

Browse files
committed
Leniently handle lambda-defined listeners with ErrorHandler as well
Issue: SPR-15838 (cherry picked from commit dd2bbcb)
1 parent 0088922 commit f948742

File tree

2 files changed

+46
-17
lines changed

2 files changed

+46
-17
lines changed

spring-context/src/main/java/org/springframework/context/event/SimpleApplicationEventMulticaster.java

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -151,34 +151,38 @@ private ResolvableType resolveDefaultEventType(ApplicationEvent event) {
151151
* @param event the current event to propagate
152152
* @since 4.1
153153
*/
154-
@SuppressWarnings({"unchecked", "rawtypes"})
155-
protected void invokeListener(ApplicationListener listener, ApplicationEvent event) {
154+
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
156155
ErrorHandler errorHandler = getErrorHandler();
157156
if (errorHandler != null) {
158157
try {
159-
listener.onApplicationEvent(event);
158+
doInvokeListener(listener, event);
160159
}
161160
catch (Throwable err) {
162161
errorHandler.handleError(err);
163162
}
164163
}
165164
else {
166-
try {
167-
listener.onApplicationEvent(event);
168-
}
169-
catch (ClassCastException ex) {
170-
String msg = ex.getMessage();
171-
if (msg == null || msg.startsWith(event.getClass().getName())) {
172-
// Possibly a lambda-defined listener which we could not resolve the generic event type for
173-
Log logger = LogFactory.getLog(getClass());
174-
if (logger.isDebugEnabled()) {
175-
logger.debug("Non-matching event type for listener: " + listener, ex);
176-
}
177-
}
178-
else {
179-
throw ex;
165+
doInvokeListener(listener, event);
166+
}
167+
}
168+
169+
@SuppressWarnings({"unchecked", "rawtypes"})
170+
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
171+
try {
172+
listener.onApplicationEvent(event);
173+
}
174+
catch (ClassCastException ex) {
175+
String msg = ex.getMessage();
176+
if (msg == null || msg.startsWith(event.getClass().getName())) {
177+
// Possibly a lambda-defined listener which we could not resolve the generic event type for
178+
Log logger = LogFactory.getLog(getClass());
179+
if (logger.isDebugEnabled()) {
180+
logger.debug("Non-matching event type for listener: " + listener, ex);
180181
}
181182
}
183+
else {
184+
throw ex;
185+
}
182186
}
183187
}
184188

spring-context/src/test/java/org/springframework/context/event/ApplicationContextEventTests.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import org.springframework.core.annotation.Order;
4747
import org.springframework.scheduling.support.TaskUtils;
4848
import org.springframework.tests.sample.beans.TestBean;
49+
import org.springframework.util.ReflectionUtils;
4950

5051
import static org.junit.Assert.*;
5152
import static org.mockito.BDDMockito.*;
@@ -447,6 +448,30 @@ public void lambdaAsListener() {
447448
context.close();
448449
}
449450

451+
@Test
452+
public void lambdaAsListenerWithErrorHandler() {
453+
final Set<MyEvent> seenEvents = new HashSet<>();
454+
StaticApplicationContext context = new StaticApplicationContext();
455+
SimpleApplicationEventMulticaster multicaster = new SimpleApplicationEventMulticaster();
456+
multicaster.setErrorHandler(ReflectionUtils::rethrowRuntimeException);
457+
context.getBeanFactory().registerSingleton(
458+
StaticApplicationContext.APPLICATION_EVENT_MULTICASTER_BEAN_NAME, multicaster);
459+
ApplicationListener<MyEvent> listener = seenEvents::add;
460+
context.addApplicationListener(listener);
461+
context.refresh();
462+
463+
MyEvent event1 = new MyEvent(context);
464+
context.publishEvent(event1);
465+
context.publishEvent(new MyOtherEvent(context));
466+
MyEvent event2 = new MyEvent(context);
467+
context.publishEvent(event2);
468+
assertSame(2, seenEvents.size());
469+
assertTrue(seenEvents.contains(event1));
470+
assertTrue(seenEvents.contains(event2));
471+
472+
context.close();
473+
}
474+
450475
@Test
451476
public void beanPostProcessorPublishesEvents() {
452477
GenericApplicationContext context = new GenericApplicationContext();

0 commit comments

Comments
 (0)