From fc55e66d50041893def2490f8f97dbffc9066454 Mon Sep 17 00:00:00 2001 From: Steven Schlansker Date: Fri, 11 Oct 2019 13:55:50 -0700 Subject: [PATCH] ApplicationListenerMethodAdapter: gracefully handle beans which are actually NullBean Currently, if you have an optional event listener (via a @Bean method returning `null`) this causes the event multicaster to explode violently. Now, we just safely skip it. --- .../ApplicationListenerMethodAdapter.java | 3 ++ .../AnnotationDrivenEventListenerTests.java | 38 +++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/spring-context/src/main/java/org/springframework/context/event/ApplicationListenerMethodAdapter.java b/spring-context/src/main/java/org/springframework/context/event/ApplicationListenerMethodAdapter.java index e352d69ad3..9cef8e78d4 100644 --- a/spring-context/src/main/java/org/springframework/context/event/ApplicationListenerMethodAdapter.java +++ b/spring-context/src/main/java/org/springframework/context/event/ApplicationListenerMethodAdapter.java @@ -295,6 +295,9 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe @Nullable protected Object doInvoke(Object... args) { Object bean = getTargetBean(); + if (bean.equals(null)) { + return null; + } ReflectionUtils.makeAccessible(this.method); try { return this.method.invoke(bean, args); 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 ae502c6303..fbe6a67d2e 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 @@ -16,6 +16,8 @@ package org.springframework.context.event; +import java.io.Closeable; +import java.io.IOException; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -24,12 +26,14 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedHashSet; import java.util.List; +import java.util.Optional; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import javax.annotation.PostConstruct; +import javax.inject.Inject; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Disabled; @@ -622,6 +626,12 @@ public class AnnotationDrivenEventListenerTests { assertThat(listener.order).contains("first", "second", "third"); } + @Test + public void missingBeanDoesntCrash() { + load(MissingEventListener.class); + context.getBean(UseMissingEventListener.class); + context.getBean(ApplicationEventMulticaster.class).multicastEvent(new TestEvent(this)); + } private void load(Class... classes) { List> allClasses = new ArrayList<>(); @@ -1076,4 +1086,32 @@ public class AnnotationDrivenEventListenerTests { } } + @Configuration + @Import({UseMissingEventListener.class}) + public static class MissingEventListener { + @Bean + public MyEventListener missing() { + return null; + } + } + + @Component + public static class MyEventListener implements Closeable { + @EventListener + public void hear(TestEvent e) { + throw new AssertionError(); + } + + @Override + public void close() throws IOException {} + } + + public static class UseMissingEventListener { + @Inject + public UseMissingEventListener(Optional notHere) { + if (notHere.isPresent()) { + throw new AssertionError(); + } + } + } }