-
Notifications
You must be signed in to change notification settings - Fork 183
Description
Spring Modulith version: 1.4.2 (the impacted code seems to be the same in the latest version)
Hi,
We use a custom ApplicationModuleSourceFactory to load generic modules defined in a shared library.
public class GenericApplicationModuleSourceFactory implements ApplicationModuleSourceFactory {
@Override
public List<String> getRootPackages() {
return List.of("com.example.generic");
}
@Override
public @Nullable ApplicationModuleDetectionStrategy getApplicationModuleDetectionStrategy() {
return ApplicationModuleDetectionStrategy.explicitlyAnnotated();
}
}
In another repo, an application is defined under the package com.example.app. It includes the shared library, including GenericApplicationModuleSourceFactory and the modules defined under com.example.generic.
The loading of the generic modules in our application works fine. But running the architecture tests with the following code fails with an unexpected exception.
import com.example.app.ModulithicApplication;
class ArchitectureTest {
private final ApplicationModules modules =
ApplicationModules.of(ModulithicApplication.class, location -> true);
@Test
void verifyArchitecture() {
modules
.detectViolations(VerificationOptions.defaults())
.throwIfPresent();
}
}
The exception raised has the following stacktrace where the user-management module is defined in the package com.example.generic.usermanagement.
Rule 'slices assigned from Appliction module slices [user-management] should be free of cycles' failed to check any classes. This means either that no classes have been passed to the rule at all, or that no classes passed to the rule matched the `that()` clause. To allow rules being evaluated without checking any classes you can either use `ArchRule.allowEmptyShould(true)` on a single rule or set the configuration property `archRule.failOnEmptyShould = false` to change the behavior globally.
java.lang.AssertionError: Rule 'slices assigned from Appliction module slices [user-management] should be free of cycles' failed to check any classes. This means either that no classes have been passed to the rule at all, or that no classes passed to the rule matched the `that()` clause. To allow rules being evaluated without checking any classes you can either use `ArchRule.allowEmptyShould(true)` on a single rule or set the configuration property `archRule.failOnEmptyShould = false` to change the behavior globally.
at com.tngtech.archunit.lang.ArchRule$Factory$SimpleArchRule.verifyNoEmptyShouldIfEnabled(ArchRule.java:201)
at com.tngtech.archunit.lang.ArchRule$Factory$SimpleArchRule.evaluate(ArchRule.java:181)
at com.tngtech.archunit.lang.syntax.ObjectsShouldInternal.evaluate(ObjectsShouldInternal.java:76)
at com.tngtech.archunit.library.dependencies.SliceRule.evaluate(SliceRule.java:99)
at org.springframework.modulith.core.ApplicationModules.assertNoCyclesFor(ApplicationModules.java:627)
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
at java.base/java.util.AbstractList$RandomAccessSpliterator.forEachRemaining(AbstractList.java:722)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682)
at org.springframework.modulith.core.ApplicationModules.detectViolations(ApplicationModules.java:496)
...
In ApplicationModules, the property allClasses includes classes under com.example.app, but not the classes of modules loaded with an ApplicationModuleSourceFactory (no class from com.example.generic). On the other hand, the field rootPackages does contain the root packages com.example.generic added by the factory. In ApplicationModules#detectViolations, the method ApplicationModules#assertNoCyclesFor is called for each rootPackages. This method fails on com.example.generic because allClasses does not contain the classes of that package, and the rule does not have SliceRule#allowEmptyShould(true).
Do you confirm that's a bug, or is there anything wrong with our configuration?
Let me know if you need a minimal example project to reproduce the issue.