From 19db2339bd895a3b898dc8e21bdcca4779898ba9 Mon Sep 17 00:00:00 2001 From: Oliver Drotbohm Date: Fri, 21 Feb 2025 22:49:28 +0100 Subject: [PATCH] GH-1062 - ApplicationModuleExporter now exposes ApplicationModuleInitializer beans. --- .../modulith/core/ApplicationModule.java | 17 +++++++++++++++++ .../modulith/core/SpringBean.java | 13 +++++++++++++ .../core/util/ApplicationModulesExporter.java | 6 ++++++ spring-modulith-integration-test/pom.xml | 7 +++++++ .../myproject/moduleA/ServiceComponentA.java | 6 +++++- .../ApplicationModulesExporterUnitTests.java | 10 ++++++++++ 6 files changed, 58 insertions(+), 1 deletion(-) diff --git a/spring-modulith-core/src/main/java/org/springframework/modulith/core/ApplicationModule.java b/spring-modulith-core/src/main/java/org/springframework/modulith/core/ApplicationModule.java index afd97bd0..8e495e6d 100644 --- a/spring-modulith-core/src/main/java/org/springframework/modulith/core/ApplicationModule.java +++ b/spring-modulith-core/src/main/java/org/springframework/modulith/core/ApplicationModule.java @@ -301,6 +301,23 @@ public class ApplicationModule implements Comparable { .toList(); } + /** + * Returns all {@link SpringBean}s assignable to the given type. + * + * @param type must not be {@literal null}. + * @return will never be {@literal null}. + * @since 1.4 + */ + public List getSpringBeans(Class type) { + + Assert.notNull(type, "Type must not be null!"); + + return getSpringBeansInternal().stream() // + .map(it -> SpringBean.of(it, this)) // + .filter(it -> it.isAssignableTo(type)) + .toList(); + } + /** * Returns the {@link ArchitecturallyEvidentType} for the given type. * diff --git a/spring-modulith-core/src/main/java/org/springframework/modulith/core/SpringBean.java b/spring-modulith-core/src/main/java/org/springframework/modulith/core/SpringBean.java index 788518f5..2b77f126 100644 --- a/spring-modulith-core/src/main/java/org/springframework/modulith/core/SpringBean.java +++ b/spring-modulith-core/src/main/java/org/springframework/modulith/core/SpringBean.java @@ -106,6 +106,19 @@ public class SpringBean { return ArchitecturallyEvidentType.of(type, module.getSpringBeansInternal()); } + /** + * Returns whether the bean is assignable to the given type. + * + * @param type must not be {@literal null}. + * @since 1.4 + */ + public boolean isAssignableTo(Class type) { + + Assert.notNull(type, "Type must not be null!"); + + return this.type.isAssignableTo(type); + } + /* * (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) diff --git a/spring-modulith-core/src/main/java/org/springframework/modulith/core/util/ApplicationModulesExporter.java b/spring-modulith-core/src/main/java/org/springframework/modulith/core/util/ApplicationModulesExporter.java index 0e344e50..5e2cc9e4 100644 --- a/spring-modulith-core/src/main/java/org/springframework/modulith/core/util/ApplicationModulesExporter.java +++ b/spring-modulith-core/src/main/java/org/springframework/modulith/core/util/ApplicationModulesExporter.java @@ -30,6 +30,7 @@ import java.util.stream.Collector; import java.util.stream.Collectors; import java.util.stream.Stream; +import org.springframework.modulith.ApplicationModuleInitializer; import org.springframework.modulith.core.ApplicationModule; import org.springframework.modulith.core.ApplicationModuleDependency; import org.springframework.modulith.core.ApplicationModuleIdentifier; @@ -37,6 +38,7 @@ import org.springframework.modulith.core.ApplicationModules; import org.springframework.modulith.core.DependencyType; import org.springframework.modulith.core.NamedInterface; import org.springframework.modulith.core.NamedInterfaces; +import org.springframework.modulith.core.SpringBean; import org.springframework.util.Assert; import com.tngtech.archunit.core.domain.JavaClass; @@ -137,6 +139,10 @@ public class ApplicationModulesExporter { if (details.equals(Details.FULL)) { json.put("namedInterfaces", toNamedInterfaces(module.getNamedInterfaces())); + json.put("initializers", module.getSpringBeans(ApplicationModuleInitializer.class).stream() + .map(SpringBean::getType) + .map(JavaClass::getName) + .toList()); } json.put("dependencies", module.getDirectDependencies(modules).stream() // diff --git a/spring-modulith-integration-test/pom.xml b/spring-modulith-integration-test/pom.xml index 7b3f0505..88a5ee72 100644 --- a/spring-modulith-integration-test/pom.xml +++ b/spring-modulith-integration-test/pom.xml @@ -23,6 +23,13 @@ ${project.version} + + ${project.groupId} + spring-modulith-runtime + ${project.version} + test + + ${project.groupId} spring-modulith-test diff --git a/spring-modulith-integration-test/src/main/java/com/acme/myproject/moduleA/ServiceComponentA.java b/spring-modulith-integration-test/src/main/java/com/acme/myproject/moduleA/ServiceComponentA.java index 0802da3f..4f2bc16c 100644 --- a/spring-modulith-integration-test/src/main/java/com/acme/myproject/moduleA/ServiceComponentA.java +++ b/spring-modulith-integration-test/src/main/java/com/acme/myproject/moduleA/ServiceComponentA.java @@ -16,13 +16,14 @@ package com.acme.myproject.moduleA; import org.springframework.context.ApplicationEventPublisher; +import org.springframework.modulith.ApplicationModuleInitializer; import org.springframework.stereotype.Component; /** * @author Oliver Drotbohm */ @Component -public class ServiceComponentA { +public class ServiceComponentA implements ApplicationModuleInitializer { private final ApplicationEventPublisher publisher; @@ -33,4 +34,7 @@ public class ServiceComponentA { public void fireEvent() { publisher.publishEvent(new SomeEventA("Message")); } + + @Override + public void initialize() {} } diff --git a/spring-modulith-integration-test/src/test/java/org/springframework/modulith/core/util/ApplicationModulesExporterUnitTests.java b/spring-modulith-integration-test/src/test/java/org/springframework/modulith/core/util/ApplicationModulesExporterUnitTests.java index 7fdbceee..f046f2e4 100644 --- a/spring-modulith-integration-test/src/test/java/org/springframework/modulith/core/util/ApplicationModulesExporterUnitTests.java +++ b/spring-modulith-integration-test/src/test/java/org/springframework/modulith/core/util/ApplicationModulesExporterUnitTests.java @@ -23,6 +23,7 @@ import org.junit.jupiter.api.Test; import org.springframework.modulith.core.ApplicationModules; import com.acme.myproject.Application; +import com.acme.myproject.moduleA.ServiceComponentA; import com.fasterxml.jackson.databind.ObjectMapper; import com.jayway.jsonpath.JsonPath; @@ -61,4 +62,13 @@ class ApplicationModulesExporterUnitTests { new ObjectMapper().readTree(EXPORTER.toJson()); }); } + + @Test // GH-1062 + void fullRenderingListsInitializers() { + + var exported = EXPORTER.toFullJson(); + + assertThat((List) JsonPath.compile("$..initializers[*]").read(exported)) + .containsExactly(ServiceComponentA.class.getName()); + } }