From 433a22559eaaae7a75e8533890f6fc5e43249ad6 Mon Sep 17 00:00:00 2001 From: Oliver Drotbohm Date: Mon, 17 Mar 2025 19:01:53 +0100 Subject: [PATCH] GH-1110 - Register AssertablePublishedEvents in ApplicationContext if AssertJ is on the classpath. We now check for the presence of AssertJ on the classpath and rather register an instance of ApplicationPublishedEvents in the ApplicationContext if present. --- .../test/ModuleContextCustomizerFactory.java | 2 +- .../modulith/test/PublishedEventsFactory.java | 51 +++++++++++++++++++ .../PublishedEventsParameterResolver.java | 11 ++-- .../ModuleContextCustomizerUnitTests.java | 17 +++++++ 4 files changed, 72 insertions(+), 9 deletions(-) create mode 100644 spring-modulith-test/src/main/java/org/springframework/modulith/test/PublishedEventsFactory.java diff --git a/spring-modulith-test/src/main/java/org/springframework/modulith/test/ModuleContextCustomizerFactory.java b/spring-modulith-test/src/main/java/org/springframework/modulith/test/ModuleContextCustomizerFactory.java index 8ae3c3f0..ec331dc8 100644 --- a/spring-modulith-test/src/main/java/org/springframework/modulith/test/ModuleContextCustomizerFactory.java +++ b/spring-modulith-test/src/main/java/org/springframework/modulith/test/ModuleContextCustomizerFactory.java @@ -84,7 +84,7 @@ class ModuleContextCustomizerFactory implements ContextCustomizerFactory { beanFactory.registerSingleton(ModuleTestExecutionBeanDefinitionSelector.class.getName(), new ModuleTestExecutionBeanDefinitionSelector(testExecution)); - var events = new DefaultPublishedEvents(); + var events = PublishedEventsFactory.createPublishedEvents(); beanFactory.registerSingleton(events.getClass().getName(), events); context.addApplicationListener(events); } diff --git a/spring-modulith-test/src/main/java/org/springframework/modulith/test/PublishedEventsFactory.java b/spring-modulith-test/src/main/java/org/springframework/modulith/test/PublishedEventsFactory.java new file mode 100644 index 00000000..6094eb62 --- /dev/null +++ b/spring-modulith-test/src/main/java/org/springframework/modulith/test/PublishedEventsFactory.java @@ -0,0 +1,51 @@ +/* + * Copyright 2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.modulith.test; + +import org.springframework.context.ApplicationEvent; +import org.springframework.context.ApplicationListener; +import org.springframework.util.ClassUtils; + +/** + * Creates an instance of {@link PublishedEvents} or {@link AssertablePublishedEvents} depending on whether AssertJ is + * on the classpath or not. + * + * @author Oliver Drotbohm + * @since 1.4 + */ +class PublishedEventsFactory { + + private static final boolean ASSERT_J_PRESENT = ClassUtils.isPresent("org.assertj.core.api.Assert", + PublishedEventsParameterResolver.class.getClassLoader()); + + /** + * Returns whether AssertJ is present or not. + */ + static boolean isAssertJPresent() { + return ASSERT_J_PRESENT; + } + + /** + * Creates a instance of {@link PublishedEvents} that's also an {@link ApplicationListener} for + * {@link ApplicationEvent}s. + * + * @return will never be {@literal null}. + */ + @SuppressWarnings("unchecked") + static > T createPublishedEvents() { + return (T) (isAssertJPresent() ? new DefaultAssertablePublishedEvents() : new DefaultPublishedEvents()); + } +} diff --git a/spring-modulith-test/src/main/java/org/springframework/modulith/test/PublishedEventsParameterResolver.java b/spring-modulith-test/src/main/java/org/springframework/modulith/test/PublishedEventsParameterResolver.java index 639a2d82..a7c964bc 100644 --- a/spring-modulith-test/src/main/java/org/springframework/modulith/test/PublishedEventsParameterResolver.java +++ b/spring-modulith-test/src/main/java/org/springframework/modulith/test/PublishedEventsParameterResolver.java @@ -27,7 +27,6 @@ import org.springframework.context.ApplicationListener; import org.springframework.context.support.AbstractApplicationContext; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; /** * Provides instances of {@link PublishedEvents} as test method parameters. @@ -36,9 +35,6 @@ import org.springframework.util.ClassUtils; */ class PublishedEventsParameterResolver implements ParameterResolver, AfterEachCallback { - private static final boolean ASSERT_J_PRESENT = ClassUtils.isPresent("org.assertj.core.api.Assert", - PublishedEventsParameterResolver.class.getClassLoader()); - private ThreadBoundApplicationListenerAdapter listener; private final Function lookup; @@ -59,7 +55,8 @@ class PublishedEventsParameterResolver implements ParameterResolver, AfterEachCa var type = parameterContext.getParameter().getType(); - if (type.getName().equals("org.springframework.modulith.test.AssertablePublishedEvents") && !ASSERT_J_PRESENT) { + if (type.getName().equals("org.springframework.modulith.test.AssertablePublishedEvents") + && !PublishedEventsFactory.isAssertJPresent()) { throw new IllegalStateException( "Method declares AssertablePublishedEvents as parameter but AssertJ is not on the classpath!"); } @@ -74,9 +71,7 @@ class PublishedEventsParameterResolver implements ParameterResolver, AfterEachCa @Override public PublishedEvents resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) { - var publishedEvents = ASSERT_J_PRESENT - ? new DefaultAssertablePublishedEvents() - : new DefaultPublishedEvents(); + var publishedEvents = PublishedEventsFactory.createPublishedEvents(); initializeListener(extensionContext); listener.registerDelegate(publishedEvents); diff --git a/spring-modulith-test/src/test/java/org/springframework/modulith/test/ModuleContextCustomizerUnitTests.java b/spring-modulith-test/src/test/java/org/springframework/modulith/test/ModuleContextCustomizerUnitTests.java index 58fbd8fc..9996394c 100644 --- a/spring-modulith-test/src/test/java/org/springframework/modulith/test/ModuleContextCustomizerUnitTests.java +++ b/spring-modulith-test/src/test/java/org/springframework/modulith/test/ModuleContextCustomizerUnitTests.java @@ -21,9 +21,12 @@ import example.module.SampleTestA; import example.module.SampleTestB; import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.modulith.core.ApplicationModule; import org.springframework.modulith.core.ApplicationModuleIdentifier; import org.springframework.modulith.test.ModuleContextCustomizerFactory.ModuleContextCustomizer; +import org.springframework.test.context.MergedContextConfiguration; +import org.springframework.test.context.support.AnnotationConfigContextLoader; /** * Unit tests for {@link ModuleTypeExcludeFilter}. @@ -65,4 +68,18 @@ class ModuleContextCustomizerUnitTests { assertThat(right).isEqualTo(left); assertThat(left).hasSameHashCodeAs(right); } + + @Test // GH-1110 + void registersAssertablePublishedEvents() { + + var context = new AnnotationConfigApplicationContext(); + var loader = new AnnotationConfigContextLoader(); + + new ModuleContextCustomizer(SampleTestA.class) + .customizeContext(context, new MergedContextConfiguration(SampleTestA.class, null, null, null, loader)); + + assertThat(context.getApplicationListeners()).hasSize(1) + .element(0) + .isInstanceOf(AssertablePublishedEvents.class); + } }