diff --git a/spring-modulith-core/src/main/java/org/springframework/modulith/core/ApplicationModuleInformation.java b/spring-modulith-core/src/main/java/org/springframework/modulith/core/ApplicationModuleInformation.java
index 4e1d1e5e..800c8d18 100644
--- a/spring-modulith-core/src/main/java/org/springframework/modulith/core/ApplicationModuleInformation.java
+++ b/spring-modulith-core/src/main/java/org/springframework/modulith/core/ApplicationModuleInformation.java
@@ -15,30 +15,17 @@
*/
package org.springframework.modulith.core;
-import java.lang.annotation.Annotation;
-import java.util.Arrays;
import java.util.List;
import java.util.Optional;
-import java.util.function.Predicate;
-import java.util.function.Supplier;
-import java.util.stream.Stream;
-
-import org.jmolecules.ddd.annotation.Module;
-import org.springframework.modulith.ApplicationModule;
-import org.springframework.modulith.ApplicationModule.Type;
-import org.springframework.modulith.core.Types.JMoleculesTypes;
-import org.springframework.util.Assert;
-import org.springframework.util.StringUtils;
-
-import com.tngtech.archunit.core.domain.JavaClass;
/**
* Abstraction for low-level module information. Used to support different annotations to configure metadata about a
* module.
*
* @author Oliver Drotbohm
+ * @since 1.4, previously package private.
*/
-interface ApplicationModuleInformation {
+public interface ApplicationModuleInformation {
/**
* Creates a new {@link ApplicationModuleInformation} for the given {@link JavaPackage}.
@@ -47,12 +34,7 @@ interface ApplicationModuleInformation {
* @return will never be {@literal null}.
*/
public static ApplicationModuleInformation of(JavaPackage javaPackage) {
-
- var lookup = AnnotationLookup.of(javaPackage.toSingle(), __ -> true);
-
- return JMoleculesTypes.isModulePresent() && JMoleculesModule.supports(lookup)
- ? new JMoleculesModule(lookup)
- : new SpringModulithModule(lookup);
+ return ApplicationModuleInformationFactory.of(javaPackage);
}
/**
@@ -78,140 +60,4 @@ interface ApplicationModuleInformation {
* @since 1.2
*/
boolean isOpen();
-
- /**
- * An {@link ApplicationModuleInformation} for the jMolecules {@link Module} annotation.
- *
- * @author Oliver Drotbohm
- * @see https://jMolecules.org
- */
- static class JMoleculesModule implements ApplicationModuleInformation {
-
- private final Optional annotation;
-
- public static boolean supports(AnnotationLookup lookup) {
- return lookup.lookup(Module.class).isPresent();
- }
-
- public JMoleculesModule(AnnotationLookup lookup) {
- this.annotation = lookup.lookup(Module.class);
- }
-
- /*
- * (non-Javadoc)
- * @see org.springframework.modulith.model.ApplicationModuleInformation#getDisplayName()
- */
- @Override
- public Optional getDisplayName() {
-
- Supplier> fallback = () -> annotation //
- .map(Module::value) //
- .filter(StringUtils::hasText);
-
- return annotation //
- .map(Module::name) //
- .filter(StringUtils::hasText)
- .or(fallback);
- }
-
- /*
- * (non-Javadoc)
- * @see org.springframework.modulith.core.ApplicationModuleInformation#getDeclaredDependencies()
- */
- @Override
- public List getDeclaredDependencies() {
- return List.of(ApplicationModule.OPEN_TOKEN);
- }
-
- /*
- * (non-Javadoc)
- * @see org.springframework.modulith.core.ApplicationModuleInformation#isOpenModule()
- */
- @Override
- public boolean isOpen() {
- return false;
- }
- }
-
- /**
- * An {@link ApplicationModuleInformation} that inspects the {@link ApplicationModule} annotation.
- *
- * @author Oliver Drotbohm
- */
- static class SpringModulithModule implements ApplicationModuleInformation {
-
- private final Optional annotation;
-
- /**
- * Whether the given {@link AnnotationLookup} supports this {@link ApplicationModuleInformation}.
- *
- * @param lookup must not be {@literal null}.
- */
- public static boolean supports(AnnotationLookup lookup) {
-
- Assert.notNull(lookup, "Annotation lookup must not be null!");
-
- return lookup.lookup(ApplicationModule.class).isPresent();
- }
-
- /**
- * Creates a new {@link SpringModulithModule} for the given {@link AnnotationLookup}.
- *
- * @param lookup must not be {@literal null}.
- */
- public SpringModulithModule(AnnotationLookup lookup) {
- this.annotation = lookup.lookup(ApplicationModule.class);
- }
-
- /*
- * (non-Javadoc)
- * @see org.springframework.modulith.model.ApplicationModuleInformation#getDisplayName()
- */
- @Override
- public Optional getDisplayName() {
-
- return annotation //
- .map(ApplicationModule::displayName) //
- .filter(StringUtils::hasText);
- }
-
- /*
- * (non-Javadoc)
- * @see org.springframework.modulith.core.ApplicationModuleInformation#getDeclaredDependencies()
- */
- @Override
- public List getDeclaredDependencies() {
-
- return annotation //
- .map(it -> Arrays.stream(it.allowedDependencies())) //
- .orElse(Stream.of(ApplicationModule.OPEN_TOKEN)) //
- .toList();
- }
-
- /*
- * (non-Javadoc)
- * @see org.springframework.modulith.core.ApplicationModuleInformation#isOpenModule()
- */
- @Override
- public boolean isOpen() {
- return annotation.map(it -> it.type().equals(Type.OPEN)).orElse(false);
- }
- }
-
- interface AnnotationLookup {
-
- static AnnotationLookup of(JavaPackage javaPackage,
- Predicate typeSelector) {
-
- return new AnnotationLookup() {
-
- @Override
- public Optional lookup(Class annotation) {
- return javaPackage.findAnnotation(annotation);
- }
- };
- }
-
- Optional lookup(Class annotation);
- }
}
diff --git a/spring-modulith-core/src/main/java/org/springframework/modulith/core/ApplicationModuleInformationFactory.java b/spring-modulith-core/src/main/java/org/springframework/modulith/core/ApplicationModuleInformationFactory.java
new file mode 100644
index 00000000..03d472f3
--- /dev/null
+++ b/spring-modulith-core/src/main/java/org/springframework/modulith/core/ApplicationModuleInformationFactory.java
@@ -0,0 +1,193 @@
+/*
+ * 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.core;
+
+import java.lang.annotation.Annotation;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+
+import org.jmolecules.ddd.annotation.Module;
+import org.springframework.modulith.ApplicationModule;
+import org.springframework.modulith.ApplicationModule.Type;
+import org.springframework.modulith.core.Types.JMoleculesTypes;
+import org.springframework.util.Assert;
+import org.springframework.util.StringUtils;
+
+import com.tngtech.archunit.core.domain.JavaClass;
+
+/**
+ * Encapsulate creation logic for {@link ApplicationModuleInformation} instances.
+ *
+ * @author Oliver Drotbohm
+ * @since 1.4
+ */
+class ApplicationModuleInformationFactory {
+
+ /**
+ * Creates a new {@link ApplicationModuleInformation} for the given {@link JavaPackage}.
+ *
+ * @param javaPackage must not be {@literal null}.
+ * @return will never be {@literal null}.
+ */
+ public static ApplicationModuleInformation of(JavaPackage javaPackage) {
+
+ var lookup = AnnotationLookup.of(javaPackage.toSingle(), __ -> true);
+
+ return JMoleculesTypes.isModulePresent() && JMoleculesModule.supports(lookup)
+ ? new JMoleculesModule(lookup)
+ : new SpringModulithModule(lookup);
+ }
+
+ /**
+ * An {@link ApplicationModuleInformation} for the jMolecules {@link Module} annotation.
+ *
+ * @author Oliver Drotbohm
+ * @see https://jMolecules.org
+ */
+ static class JMoleculesModule implements ApplicationModuleInformation {
+
+ private final Optional annotation;
+
+ public static boolean supports(AnnotationLookup lookup) {
+ return lookup.lookup(Module.class).isPresent();
+ }
+
+ public JMoleculesModule(AnnotationLookup lookup) {
+ this.annotation = lookup.lookup(Module.class);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.modulith.model.ApplicationModuleInformation#getDisplayName()
+ */
+ @Override
+ public Optional getDisplayName() {
+
+ Supplier> fallback = () -> annotation //
+ .map(Module::value) //
+ .filter(StringUtils::hasText);
+
+ return annotation //
+ .map(Module::name) //
+ .filter(StringUtils::hasText)
+ .or(fallback);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.modulith.core.ApplicationModuleInformation#getDeclaredDependencies()
+ */
+ @Override
+ public List getDeclaredDependencies() {
+ return List.of(ApplicationModule.OPEN_TOKEN);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.modulith.core.ApplicationModuleInformation#isOpenModule()
+ */
+ @Override
+ public boolean isOpen() {
+ return false;
+ }
+ }
+
+ /**
+ * An {@link ApplicationModuleInformation} that inspects the {@link ApplicationModule} annotation.
+ *
+ * @author Oliver Drotbohm
+ */
+ static class SpringModulithModule implements ApplicationModuleInformation {
+
+ private final Optional annotation;
+
+ /**
+ * Whether the given {@link AnnotationLookup} supports this {@link ApplicationModuleInformation}.
+ *
+ * @param lookup must not be {@literal null}.
+ */
+ public static boolean supports(AnnotationLookup lookup) {
+
+ Assert.notNull(lookup, "Annotation lookup must not be null!");
+
+ return lookup.lookup(ApplicationModule.class).isPresent();
+ }
+
+ /**
+ * Creates a new {@link SpringModulithModule} for the given {@link AnnotationLookup}.
+ *
+ * @param lookup must not be {@literal null}.
+ */
+ public SpringModulithModule(AnnotationLookup lookup) {
+ this.annotation = lookup.lookup(ApplicationModule.class);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.modulith.model.ApplicationModuleInformation#getDisplayName()
+ */
+ @Override
+ public Optional getDisplayName() {
+
+ return annotation //
+ .map(ApplicationModule::displayName) //
+ .filter(StringUtils::hasText);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.modulith.core.ApplicationModuleInformation#getDeclaredDependencies()
+ */
+ @Override
+ public List getDeclaredDependencies() {
+
+ return annotation //
+ .map(it -> Arrays.stream(it.allowedDependencies())) //
+ .orElse(Stream.of(ApplicationModule.OPEN_TOKEN)) //
+ .toList();
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.modulith.core.ApplicationModuleInformation#isOpenModule()
+ */
+ @Override
+ public boolean isOpen() {
+ return annotation.map(it -> it.type().equals(Type.OPEN)).orElse(false);
+ }
+ }
+
+ interface AnnotationLookup {
+
+ static AnnotationLookup of(JavaPackage javaPackage,
+ Predicate typeSelector) {
+
+ return new AnnotationLookup() {
+
+ @Override
+ public Optional lookup(Class annotation) {
+ return javaPackage.findAnnotation(annotation);
+ }
+ };
+ }
+
+ Optional lookup(Class annotation);
+ }
+}