Browse Source

Leniently handle lambda-defined listeners with ErrorHandler as well

Issue: SPR-15838
pull/1489/head
Juergen Hoeller 7 years ago
parent
commit
dd2bbcb3ec
  1. 38
      spring-context/src/main/java/org/springframework/context/event/SimpleApplicationEventMulticaster.java
  2. 25
      spring-context/src/test/java/org/springframework/context/event/ApplicationContextEventTests.java

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

@ -151,34 +151,38 @@ public class SimpleApplicationEventMulticaster extends AbstractApplicationEventM @@ -151,34 +151,38 @@ public class SimpleApplicationEventMulticaster extends AbstractApplicationEventM
* @param event the current event to propagate
* @since 4.1
*/
@SuppressWarnings({"unchecked", "rawtypes"})
protected void invokeListener(ApplicationListener listener, ApplicationEvent event) {
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
try {
listener.onApplicationEvent(event);
doInvokeListener(listener, event);
}
catch (Throwable err) {
errorHandler.handleError(err);
}
}
else {
try {
listener.onApplicationEvent(event);
}
catch (ClassCastException ex) {
String msg = ex.getMessage();
if (msg == null || msg.startsWith(event.getClass().getName())) {
// Possibly a lambda-defined listener which we could not resolve the generic event type for
Log logger = LogFactory.getLog(getClass());
if (logger.isDebugEnabled()) {
logger.debug("Non-matching event type for listener: " + listener, ex);
}
}
else {
throw ex;
doInvokeListener(listener, event);
}
}
@SuppressWarnings({"unchecked", "rawtypes"})
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
listener.onApplicationEvent(event);
}
catch (ClassCastException ex) {
String msg = ex.getMessage();
if (msg == null || msg.startsWith(event.getClass().getName())) {
// Possibly a lambda-defined listener which we could not resolve the generic event type for
Log logger = LogFactory.getLog(getClass());
if (logger.isDebugEnabled()) {
logger.debug("Non-matching event type for listener: " + listener, ex);
}
}
else {
throw ex;
}
}
}

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

@ -46,6 +46,7 @@ import org.springframework.core.ResolvableType; @@ -46,6 +46,7 @@ import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.Order;
import org.springframework.scheduling.support.TaskUtils;
import org.springframework.tests.sample.beans.TestBean;
import org.springframework.util.ReflectionUtils;
import static org.junit.Assert.*;
import static org.mockito.BDDMockito.*;
@ -447,6 +448,30 @@ public class ApplicationContextEventTests extends AbstractApplicationEventListen @@ -447,6 +448,30 @@ public class ApplicationContextEventTests extends AbstractApplicationEventListen
context.close();
}
@Test
public void lambdaAsListenerWithErrorHandler() {
final Set<MyEvent> seenEvents = new HashSet<>();
StaticApplicationContext context = new StaticApplicationContext();
SimpleApplicationEventMulticaster multicaster = new SimpleApplicationEventMulticaster();
multicaster.setErrorHandler(ReflectionUtils::rethrowRuntimeException);
context.getBeanFactory().registerSingleton(
StaticApplicationContext.APPLICATION_EVENT_MULTICASTER_BEAN_NAME, multicaster);
ApplicationListener<MyEvent> listener = seenEvents::add;
context.addApplicationListener(listener);
context.refresh();
MyEvent event1 = new MyEvent(context);
context.publishEvent(event1);
context.publishEvent(new MyOtherEvent(context));
MyEvent event2 = new MyEvent(context);
context.publishEvent(event2);
assertSame(2, seenEvents.size());
assertTrue(seenEvents.contains(event1));
assertTrue(seenEvents.contains(event2));
context.close();
}
@Test
public void beanPostProcessorPublishesEvents() {
GenericApplicationContext context = new GenericApplicationContext();

Loading…
Cancel
Save