diff --git a/spring-modulith-core/src/main/java/org/springframework/modulith/model/ApplicationModule.java b/spring-modulith-core/src/main/java/org/springframework/modulith/model/ApplicationModule.java index c6f8e4ba..776c94e0 100644 --- a/spring-modulith-core/src/main/java/org/springframework/modulith/model/ApplicationModule.java +++ b/spring-modulith-core/src/main/java/org/springframework/modulith/model/ApplicationModule.java @@ -398,7 +398,10 @@ public class ApplicationModule { private Stream getDirectModuleBootstrapDependencies(ApplicationModules modules) { - return getSpringBeansInternal().stream() // + var beans = getSpringBeansInternal(); + + return beans.stream() // + .map(it -> ArchitecturallyEvidentType.of(it, beans)) // .flatMap(it -> ModuleDependency.fromType(it)) // .filter(it -> isDependencyToOtherModule(it.target, modules)) // .filter(it -> it.hasType(DependencyType.USES_COMPONENT)) // @@ -409,10 +412,12 @@ public class ApplicationModule { private Stream getModuleDependenciesOf(JavaClass type, ApplicationModules modules) { - Stream injections = ModuleDependency.fromType(type) // + var evidentType = ArchitecturallyEvidentType.of(type, getSpringBeansInternal()); + + var injections = ModuleDependency.fromType(evidentType) // .filter(it -> isDependencyToOtherModule(it.getTarget(), modules)); // - Stream directDependencies = type.getDirectDependenciesFromSelf().stream() // + var directDependencies = type.getDirectDependenciesFromSelf().stream() // .filter(it -> isDependencyToOtherModule(it.getTargetClass(), modules)) // .map(ModuleDependency::new); @@ -649,18 +654,27 @@ public class ApplicationModule { DependencyType.DEFAULT); } - static Stream fromType(JavaClass source) { - return Stream.concat(Stream.concat(fromConstructorOf(source), fromMethodsOf(source)), fromFieldsOf(source)); + static Stream fromType(ArchitecturallyEvidentType type) { + + JavaClass source = type.getType(); + + return Stream.concat(Stream.concat(fromConstructorOf(type), fromMethodsOf(source)), fromFieldsOf(source)); } - private static Stream fromConstructorOf(JavaClass source) { + private static Stream fromConstructorOf(ArchitecturallyEvidentType source) { - Set constructors = source.getConstructors(); + JavaClass type = source.getType(); + Set constructors = type.getConstructors(); return constructors.stream() // .filter(it -> constructors.size() == 1 || isInjectionPoint(it)) // .flatMap(it -> it.getRawParameterTypes().stream() // - .map(parameter -> new InjectionModuleDependency(source, parameter, it))); + .map(parameter -> { + return source.isConfigurationProperties() + ? new ModuleDependency(type, parameter, createDescription(it, parameter, "parameter"), + DependencyType.DEFAULT) + : new InjectionModuleDependency(type, parameter, it); + })); } private static Stream fromFieldsOf(JavaClass source) { diff --git a/spring-modulith-core/src/main/java/org/springframework/modulith/model/Classes.java b/spring-modulith-core/src/main/java/org/springframework/modulith/model/Classes.java index a2748911..1f0d3401 100644 --- a/spring-modulith-core/src/main/java/org/springframework/modulith/model/Classes.java +++ b/spring-modulith-core/src/main/java/org/springframework/modulith/model/Classes.java @@ -48,7 +48,9 @@ import com.tngtech.archunit.core.domain.properties.HasName; */ @ToString @EqualsAndHashCode -public class Classes implements DescribedIterable { +class Classes implements DescribedIterable { + + public static Classes NONE = Classes.of(Collections.emptyList()); private final List classes; diff --git a/spring-modulith-core/src/test/java/org/springframework/modulith/model/ModuleDependencyUnitTest.java b/spring-modulith-core/src/test/java/org/springframework/modulith/model/ModuleDependencyUnitTest.java index 073cdf6b..ef524524 100644 --- a/spring-modulith-core/src/test/java/org/springframework/modulith/model/ModuleDependencyUnitTest.java +++ b/spring-modulith-core/src/test/java/org/springframework/modulith/model/ModuleDependencyUnitTest.java @@ -58,7 +58,10 @@ class ModuleDependencyUnitTest { private Stream> findDependencies(Class type) { - return ModuleDependency.fromType(importer.importClass(type)) // + var imported = importer.importClass(type); + var evidentType = ArchitecturallyEvidentType.of(imported, Classes.NONE); + + return ModuleDependency.fromType(evidentType) // .map(ModuleDependency::getTarget) // .map(JavaClass::reflect); } diff --git a/spring-modulith-integration-test/src/main/java/com/acme/myproject/moduleC/SomeValueC.java b/spring-modulith-integration-test/src/main/java/com/acme/myproject/moduleC/SomeValueC.java new file mode 100644 index 00000000..8cd9ee54 --- /dev/null +++ b/spring-modulith-integration-test/src/main/java/com/acme/myproject/moduleC/SomeValueC.java @@ -0,0 +1,21 @@ +/* + * Copyright 2022 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 com.acme.myproject.moduleC; + +/** + * @author Oliver Drotbohm + */ +public class SomeValueC {} diff --git a/spring-modulith-integration-test/src/main/java/com/acme/myproject/moduleD/ConfigurationPropertiesD.java b/spring-modulith-integration-test/src/main/java/com/acme/myproject/moduleD/ConfigurationPropertiesD.java new file mode 100644 index 00000000..577e4708 --- /dev/null +++ b/spring-modulith-integration-test/src/main/java/com/acme/myproject/moduleD/ConfigurationPropertiesD.java @@ -0,0 +1,32 @@ +/* + * Copyright 2022 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 com.acme.myproject.moduleD; + +import lombok.RequiredArgsConstructor; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +import com.acme.myproject.moduleC.SomeValueC; + +/** + * @author Oliver Drotbohm + */ +@ConfigurationProperties +@RequiredArgsConstructor +class ConfigurationPropertiesD { + + private final SomeValueC value; +} diff --git a/spring-modulith-integration-test/src/test/java/com/acme/myproject/ModulithTest.java b/spring-modulith-integration-test/src/test/java/com/acme/myproject/ModulithTest.java index 6326123f..c729819a 100644 --- a/spring-modulith-integration-test/src/test/java/com/acme/myproject/ModulithTest.java +++ b/spring-modulith-integration-test/src/test/java/com/acme/myproject/ModulithTest.java @@ -19,6 +19,7 @@ import static org.assertj.core.api.Assertions.*; import org.junit.jupiter.api.Test; import org.springframework.modulith.model.ApplicationModule; +import org.springframework.modulith.model.ApplicationModule.DependencyType; import org.springframework.modulith.model.ApplicationModules; import org.springframework.modulith.model.ApplicationModules.Filters; import org.springframework.modulith.model.Violations; @@ -84,4 +85,20 @@ class ModulithTest { .doesNotContain("moduleA"); }); } + + @Test // GH-47 + void configrationPropertiesTypesEstablishSimpleDependency() { + + var modules = ApplicationModules.of(Application.class, DEFAULT_EXCLUSIONS); + + assertThat(modules.getModuleByName("moduleD")).hasValueSatisfying(it -> { + + assertThat(it.getDependencies(modules, DependencyType.DEFAULT)) + .map(ApplicationModule::getName) + .contains("moduleC"); // ConfigurationProperties -> Value + + assertThat(it.getDependencies(modules, DependencyType.USES_COMPONENT)) + .isEmpty(); + }); + } }