Skip to content

Commit 3ba9b5b

Browse files
committed
GH-599 - Invalid dependency into named interface now gets reported properly.
1 parent 8934497 commit 3ba9b5b

File tree

4 files changed

+60
-2
lines changed

4 files changed

+60
-2
lines changed

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

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,10 @@ private Classes findAggregateRoots(JavaPackage source) {
557557
.collect(Classes.toClasses());
558558
}
559559

560+
private String getQualifiedName(NamedInterface namedInterface) {
561+
return namedInterface.getQualifiedName(getName());
562+
}
563+
560564
private static Classes filterSpringBeans(JavaPackage source) {
561565

562566
Map<Boolean, List<JavaClass>> collect = source.that(isConfiguration()).stream() //
@@ -949,8 +953,20 @@ Violations isValidDependencyWithin(ApplicationModules modules) {
949953
// Check explicitly defined allowed targets
950954
if (!declaredDependencies.isAllowedDependency(target)) {
951955

952-
var message = "Module '%s' depends on module '%s' via %s -> %s. Allowed targets: %s." //
953-
.formatted(originModule.getName(), targetModule.getName(), source.getName(), target.getName(),
956+
var targetNamedInterfaces = targetModule.getNamedInterfaces()
957+
.getNamedInterfacesContaining(target)
958+
.filter(NamedInterface::isNamed)
959+
.toList();
960+
961+
var targetString = targetNamedInterfaces.isEmpty()
962+
? "module '%s'".formatted(targetModule.getName())
963+
: "named interface(s) '%s'".formatted(
964+
targetNamedInterfaces.stream()
965+
.map(targetModule::getQualifiedName)
966+
.collect(Collectors.joining(", ")));
967+
968+
var message = "Module '%s' depends on %s via %s -> %s. Allowed targets: %s." //
969+
.formatted(originModule.getName(), targetString, source.getName(), target.getName(),
954970
declaredDependencies.toString());
955971

956972
return violations.and(new Violation(message));

spring-modulith-core/src/main/java/org/springframework/modulith/core/NamedInterface.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,13 +125,24 @@ public String getName() {
125125
return name;
126126
}
127127

128+
String getQualifiedName(String qualifier) {
129+
return qualifier + " :: " + name;
130+
}
131+
128132
/**
129133
* Returns whether this is the unnamed (implicit) {@link NamedInterface}.
130134
*/
131135
public boolean isUnnamed() {
132136
return name.equals(UNNAMED_NAME);
133137
}
134138

139+
/**
140+
* Return whether this {@link NamedInterface} has an explicit name.
141+
*/
142+
public boolean isNamed() {
143+
return !isUnnamed();
144+
}
145+
135146
/**
136147
* Returns whether the {@link NamedInterface} contains the given {@link JavaClass}.
137148
*

spring-modulith-core/src/main/java/org/springframework/modulith/core/NamedInterfaces.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,20 @@ public NamedInterface getUnnamedInterface() {
138138
.orElseThrow(() -> new IllegalStateException("No unnamed interface found!"));
139139
}
140140

141+
/**
142+
* Returns all named interfaces that contain the given type.
143+
*
144+
* @param type must not be {@literal null}.
145+
* @return will never be {@literal null}.
146+
*/
147+
public Stream<NamedInterface> getNamedInterfacesContaining(JavaClass type) {
148+
149+
Assert.notNull(type, "Type must not be null!");
150+
151+
return namedInterfaces.stream()
152+
.filter(it -> it.contains(type));
153+
}
154+
141155
/*
142156
* (non-Javadoc)
143157
* @see java.lang.Iterable#iterator()
@@ -183,6 +197,12 @@ NamedInterfaces and(Iterable<NamedInterface> others) {
183197
return new NamedInterfaces(namedInterfaces);
184198
}
185199

200+
Stream<NamedInterface> getNamedInterfacesContaining(Class<?> type) {
201+
202+
return namedInterfaces.stream()
203+
.filter(it -> it.contains(type));
204+
}
205+
186206
private static NamedInterfaces of(NamedInterface interfaces) {
187207
return new NamedInterfaces(List.of(interfaces));
188208
}

spring-modulith-core/src/test/java/org/springframework/modulith/core/NamedInterfacesUnitTests.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,17 @@ void rejectsDefaultingNamedInterfaceTypeInBasePackage() {
6464
.withMessageContaining(InvalidDefaultNamedInterface.class.getSimpleName());
6565
}
6666

67+
@Test // GH-595
68+
void detectsNamedInterfacesATypeIsContainedIn() {
69+
70+
var javaPackage = TestUtils.getPackage(RootType.class);
71+
var interfaces = NamedInterfaces.discoverNamedInterfaces(javaPackage);
72+
73+
assertThat(interfaces.getNamedInterfacesContaining(AdditionalSpiType.class))
74+
.extracting(NamedInterface::getName)
75+
.containsExactlyInAnyOrder("spi", "kpi");
76+
}
77+
6778
private static void assertInterfaceContains(NamedInterfaces interfaces, String name, Class<?>... types) {
6879

6980
var classNames = Arrays.stream(types).map(Class::getName).toArray(String[]::new);

0 commit comments

Comments
 (0)