Skip to content

Commit 8591fbb

Browse files
committed
GH-47 - Treat efferent dependencies of configuration properties classes as simple dependencies.
1 parent 2430dc9 commit 8591fbb

File tree

6 files changed

+99
-10
lines changed

6 files changed

+99
-10
lines changed

spring-modulith-core/src/main/java/org/springframework/modulith/model/ApplicationModule.java

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,10 @@ private Stream<ApplicationModule> streamBootstrapDependencies(ApplicationModules
398398

399399
private Stream<ApplicationModule> getDirectModuleBootstrapDependencies(ApplicationModules modules) {
400400

401-
return getSpringBeansInternal().stream() //
401+
var beans = getSpringBeansInternal();
402+
403+
return beans.stream() //
404+
.map(it -> ArchitecturallyEvidentType.of(it, beans)) //
402405
.flatMap(it -> ModuleDependency.fromType(it)) //
403406
.filter(it -> isDependencyToOtherModule(it.target, modules)) //
404407
.filter(it -> it.hasType(DependencyType.USES_COMPONENT)) //
@@ -409,10 +412,12 @@ private Stream<ApplicationModule> getDirectModuleBootstrapDependencies(Applicati
409412

410413
private Stream<ModuleDependency> getModuleDependenciesOf(JavaClass type, ApplicationModules modules) {
411414

412-
Stream<ModuleDependency> injections = ModuleDependency.fromType(type) //
415+
var evidentType = ArchitecturallyEvidentType.of(type, getSpringBeansInternal());
416+
417+
var injections = ModuleDependency.fromType(evidentType) //
413418
.filter(it -> isDependencyToOtherModule(it.getTarget(), modules)); //
414419

415-
Stream<ModuleDependency> directDependencies = type.getDirectDependenciesFromSelf().stream() //
420+
var directDependencies = type.getDirectDependenciesFromSelf().stream() //
416421
.filter(it -> isDependencyToOtherModule(it.getTargetClass(), modules)) //
417422
.map(ModuleDependency::new);
418423

@@ -649,18 +654,27 @@ static ModuleDependency fromCodeUnitReturnType(JavaCodeUnit codeUnit) {
649654
DependencyType.DEFAULT);
650655
}
651656

652-
static Stream<ModuleDependency> fromType(JavaClass source) {
653-
return Stream.concat(Stream.concat(fromConstructorOf(source), fromMethodsOf(source)), fromFieldsOf(source));
657+
static Stream<ModuleDependency> fromType(ArchitecturallyEvidentType type) {
658+
659+
JavaClass source = type.getType();
660+
661+
return Stream.concat(Stream.concat(fromConstructorOf(type), fromMethodsOf(source)), fromFieldsOf(source));
654662
}
655663

656-
private static Stream<ModuleDependency> fromConstructorOf(JavaClass source) {
664+
private static Stream<ModuleDependency> fromConstructorOf(ArchitecturallyEvidentType source) {
657665

658-
Set<JavaConstructor> constructors = source.getConstructors();
666+
JavaClass type = source.getType();
667+
Set<JavaConstructor> constructors = type.getConstructors();
659668

660669
return constructors.stream() //
661670
.filter(it -> constructors.size() == 1 || isInjectionPoint(it)) //
662671
.flatMap(it -> it.getRawParameterTypes().stream() //
663-
.map(parameter -> new InjectionModuleDependency(source, parameter, it)));
672+
.map(parameter -> {
673+
return source.isConfigurationProperties()
674+
? new ModuleDependency(type, parameter, createDescription(it, parameter, "parameter"),
675+
DependencyType.DEFAULT)
676+
: new InjectionModuleDependency(type, parameter, it);
677+
}));
664678
}
665679

666680
private static Stream<ModuleDependency> fromFieldsOf(JavaClass source) {

spring-modulith-core/src/main/java/org/springframework/modulith/model/Classes.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@
4848
*/
4949
@ToString
5050
@EqualsAndHashCode
51-
public class Classes implements DescribedIterable<JavaClass> {
51+
class Classes implements DescribedIterable<JavaClass> {
52+
53+
public static Classes NONE = Classes.of(Collections.emptyList());
5254

5355
private final List<JavaClass> classes;
5456

spring-modulith-core/src/test/java/org/springframework/modulith/model/ModuleDependencyUnitTest.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,10 @@ public void detectsDependencyFromSingleUnannotatedConstructor() {
5858

5959
private Stream<Class<?>> findDependencies(Class<?> type) {
6060

61-
return ModuleDependency.fromType(importer.importClass(type)) //
61+
var imported = importer.importClass(type);
62+
var evidentType = ArchitecturallyEvidentType.of(imported, Classes.NONE);
63+
64+
return ModuleDependency.fromType(evidentType) //
6265
.map(ModuleDependency::getTarget) //
6366
.map(JavaClass::reflect);
6467
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* Copyright 2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.acme.myproject.moduleC;
17+
18+
/**
19+
* @author Oliver Drotbohm
20+
*/
21+
public class SomeValueC {}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright 2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.acme.myproject.moduleD;
17+
18+
import lombok.RequiredArgsConstructor;
19+
20+
import org.springframework.boot.context.properties.ConfigurationProperties;
21+
22+
import com.acme.myproject.moduleC.SomeValueC;
23+
24+
/**
25+
* @author Oliver Drotbohm
26+
*/
27+
@ConfigurationProperties
28+
@RequiredArgsConstructor
29+
class ConfigurationPropertiesD {
30+
31+
private final SomeValueC value;
32+
}

spring-modulith-integration-test/src/test/java/com/acme/myproject/ModulithTest.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
import org.junit.jupiter.api.Test;
2121
import org.springframework.modulith.model.ApplicationModule;
22+
import org.springframework.modulith.model.ApplicationModule.DependencyType;
2223
import org.springframework.modulith.model.ApplicationModules;
2324
import org.springframework.modulith.model.ApplicationModules.Filters;
2425
import org.springframework.modulith.model.Violations;
@@ -84,4 +85,20 @@ void doesNotIncludeEventListenerDependencyInBootstrapOnes() {
8485
.doesNotContain("moduleA");
8586
});
8687
}
88+
89+
@Test // GH-47
90+
void configrationPropertiesTypesEstablishSimpleDependency() {
91+
92+
var modules = ApplicationModules.of(Application.class, DEFAULT_EXCLUSIONS);
93+
94+
assertThat(modules.getModuleByName("moduleD")).hasValueSatisfying(it -> {
95+
96+
assertThat(it.getDependencies(modules, DependencyType.DEFAULT))
97+
.map(ApplicationModule::getName)
98+
.contains("moduleC"); // ConfigurationProperties -> Value
99+
100+
assertThat(it.getDependencies(modules, DependencyType.USES_COMPONENT))
101+
.isEmpty();
102+
});
103+
}
87104
}

0 commit comments

Comments
 (0)