From 4b74d4fc5a3a2cee2683505cf74eae77016ec6c8 Mon Sep 17 00:00:00 2001 From: Steven van Beelen Date: Fri, 11 Nov 2022 10:47:01 +0100 Subject: [PATCH 1/2] Check if the registration is non-null before invoking shutdown Check if the registration is non-null before invoking shutdown, as this may cause a NullPointerException. If it is null, log an info level message stating this situation. #2481 --- .../config/MessageHandlerRegistrar.java | 9 +++++++++ .../config/DefaultConfigurerTest.java | 11 +++++++++++ .../config/MessageHandlerRegistrarTest.java | 17 +++++++++++++++++ 3 files changed, 37 insertions(+) diff --git a/config/src/main/java/org/axonframework/config/MessageHandlerRegistrar.java b/config/src/main/java/org/axonframework/config/MessageHandlerRegistrar.java index 9d5406f0ff..dc956bcedd 100644 --- a/config/src/main/java/org/axonframework/config/MessageHandlerRegistrar.java +++ b/config/src/main/java/org/axonframework/config/MessageHandlerRegistrar.java @@ -19,7 +19,10 @@ import org.axonframework.common.Registration; import org.axonframework.lifecycle.Lifecycle; import org.axonframework.lifecycle.Phase; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.lang.invoke.MethodHandles; import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Supplier; @@ -39,6 +42,8 @@ */ public class MessageHandlerRegistrar implements Lifecycle { + private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + private final Supplier configurationSupplier; private final Function messageHandlerBuilder; private final BiFunction messageHandlerSubscriber; @@ -90,6 +95,10 @@ public void start() { * through the {@link #start()} method. */ public void shutdown() { + if (handlerRegistration == null) { + logger.info("Shutting down a message handler registrar before it was started."); + return; + } handlerRegistration.cancel(); } } diff --git a/config/src/test/java/org/axonframework/config/DefaultConfigurerTest.java b/config/src/test/java/org/axonframework/config/DefaultConfigurerTest.java index 06e6b792cc..925d684f38 100644 --- a/config/src/test/java/org/axonframework/config/DefaultConfigurerTest.java +++ b/config/src/test/java/org/axonframework/config/DefaultConfigurerTest.java @@ -705,6 +705,17 @@ void registeringUpcastersReturnsUpcasterChainOverRulingRegisteredUpcasterChainCo verifyNoInteractions(testUpcasterChain); } + @Test + void shuttingDownTheConfigurationBeforeItStartedWithConfiguredMessageHandlersDoesNotCauseAnyExceptions() { + Configuration configuration = DefaultConfigurer.defaultConfiguration() + .registerCommandHandler(c -> new Object()) + .registerEventHandler(c -> new Object()) + .registerQueryHandler(c -> new Object()) + .registerMessageHandler(c -> new Object()) + .buildConfiguration(); + assertDoesNotThrow(configuration::shutdown); + } + @SuppressWarnings("unused") @Entity(name = "StubAggregate") private static class StubAggregate { diff --git a/config/src/test/java/org/axonframework/config/MessageHandlerRegistrarTest.java b/config/src/test/java/org/axonframework/config/MessageHandlerRegistrarTest.java index 4807fedf8b..c3b7f7e34d 100644 --- a/config/src/test/java/org/axonframework/config/MessageHandlerRegistrarTest.java +++ b/config/src/test/java/org/axonframework/config/MessageHandlerRegistrarTest.java @@ -97,6 +97,23 @@ void shutdownCancelsMessageHandlerRegistration(@Mock Configuration config) { assertTrue(isCanceled.get()); } + @Test + void shutdownDoesNotThrowExceptionsIfWhenTheRegistrarHasNotStartedYet(@Mock Configuration config) { + AtomicBoolean isCanceled = new AtomicBoolean(false); + + MessageHandlerRegistrar testSubject = new MessageHandlerRegistrar( + () -> config, + c -> new SomeMessageHandler(), + (c, msgHandler) -> () -> { + isCanceled.set(true); + return false; + } + ); + + assertDoesNotThrow(testSubject::shutdown); + assertFalse(isCanceled.get()); + } + private static class SomeMessageHandler { private SomeMessageHandler() { From 2892e718a063e25cbdf986e04d6721de2c820df4 Mon Sep 17 00:00:00 2001 From: Steven van Beelen Date: Fri, 11 Nov 2022 10:58:55 +0100 Subject: [PATCH 2/2] Remove undesired test case Remove undesired test case #2481 --- .../config/MessageHandlerRegistrarTest.java | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/config/src/test/java/org/axonframework/config/MessageHandlerRegistrarTest.java b/config/src/test/java/org/axonframework/config/MessageHandlerRegistrarTest.java index c3b7f7e34d..45d12da493 100644 --- a/config/src/test/java/org/axonframework/config/MessageHandlerRegistrarTest.java +++ b/config/src/test/java/org/axonframework/config/MessageHandlerRegistrarTest.java @@ -65,20 +65,6 @@ void startRegistersCreatedMessageHandler(@Mock Configuration config) { assertTrue(isRegistered.get()); } - /** - * The thrown {@link NullPointerException} will always be wrapped in a {@link org.axonframework.lifecycle.LifecycleHandlerInvocationException} - * since the {@link MessageHandlerRegistrar#shutdown()} will be wrapped in a {@link LifecycleHandler}. - */ - @Test - void shutdownThrowsNullPointerExceptionIfRegistrationDidNotHappen(@Mock Configuration config) { - MessageHandlerRegistrar testSubject = new MessageHandlerRegistrar( - () -> config, c -> new SomeMessageHandler(), - (c, msgHandler) -> TEST_REGISTRATION_IMPLEMENTATION - ); - - assertThrows(NullPointerException.class, testSubject::shutdown); - } - @Test void shutdownCancelsMessageHandlerRegistration(@Mock Configuration config) { AtomicBoolean isCanceled = new AtomicBoolean(false);