GH-787 - Allow references between sibling sub-modules.
Previously, we rejected references between sub-modules both contained in the same parent package. Related ticket: GH-578.
This commit is contained in:
@@ -1201,18 +1201,17 @@ public class ApplicationModule implements Comparable<ApplicationModule> {
|
||||
|
||||
// Parent child relationships
|
||||
|
||||
return targetModule.getParentModule(modules)
|
||||
.filter(it -> !it.equals(originModule))
|
||||
.map(__ -> {
|
||||
if (!haveSameParentOrDirectParentRelationship(originModule, targetModule, modules)) {
|
||||
|
||||
var violationText = INVALID_SUB_MODULE_REFERENCE
|
||||
.formatted(originModule.getName(), targetModule.getName(),
|
||||
FormatableType.of(source).getAbbreviatedFullName(originModule),
|
||||
FormatableType.of(target).getAbbreviatedFullName(targetModule));
|
||||
var violationText = INVALID_SUB_MODULE_REFERENCE
|
||||
.formatted(originModule.getName(), targetModule.getName(),
|
||||
FormatableType.of(source).getAbbreviatedFullName(originModule),
|
||||
FormatableType.of(target).getAbbreviatedFullName(targetModule));
|
||||
|
||||
return violations.and(new Violation(violationText));
|
||||
})
|
||||
.orElse(violations);
|
||||
return violations.and(new Violation(violationText));
|
||||
}
|
||||
|
||||
return violations;
|
||||
}
|
||||
|
||||
ApplicationModule getExistingModuleOf(JavaClass javaClass, ApplicationModules modules) {
|
||||
@@ -1347,6 +1346,27 @@ public class ApplicationModule implements Comparable<ApplicationModule> {
|
||||
private static boolean isInjectionPoint(JavaMember unit) {
|
||||
return INJECTION_TYPES.stream().anyMatch(type -> unit.isAnnotatedWith(type));
|
||||
}
|
||||
|
||||
private static boolean haveSameParentOrDirectParentRelationship(ApplicationModule source, ApplicationModule target,
|
||||
ApplicationModules modules) {
|
||||
|
||||
var sourceParent = modules.getParentOf(source);
|
||||
var targetParent = modules.getParentOf(target);
|
||||
|
||||
// Top-level modules
|
||||
return targetParent.isEmpty()
|
||||
|
||||
// One is parent of the other
|
||||
|| hasValue(sourceParent, target)
|
||||
|| hasValue(targetParent, source)
|
||||
|
||||
// Same immediate parent
|
||||
|| sourceParent.flatMap(it -> targetParent.filter(it::equals)).isPresent();
|
||||
}
|
||||
|
||||
private static <T> boolean hasValue(Optional<T> optional, T expected) {
|
||||
return optional.filter(expected::equals).isPresent();
|
||||
}
|
||||
}
|
||||
|
||||
private static class InjectionDependency extends QualifiedDependency {
|
||||
|
||||
@@ -16,10 +16,12 @@
|
||||
package example.ni.nested.b.second;
|
||||
|
||||
import example.ni.nested.InNested;
|
||||
import example.ni.nested.b.first.InNestedBFirst;
|
||||
|
||||
/**
|
||||
* @author Oliver Drotbohm
|
||||
*/
|
||||
public class InNestedBSecond {
|
||||
InNested inNested;
|
||||
InNestedBFirst siblingReference;
|
||||
}
|
||||
|
||||
@@ -211,7 +211,7 @@ In this example `inventory` is an application module as described xref:fundament
|
||||
The `@ApplicationModule` annotation on the `nested` package caused that to become a nested application module in turn.
|
||||
In that arrangement, the following access rules apply:
|
||||
|
||||
* The code in _Nested_ is only available from _Inventory_, i.e. only any of the `SomethingInventoryInternal` types can access `NestedApi`. `NestedInternal` is only accessible from `NestedApi`.
|
||||
* The code in _Nested_ is only available from _Inventory_ or any types exposed by sibling application modules nested inside _Inventory_.
|
||||
* Any code in the _Nested_ module can access code in parent modules, even internal.
|
||||
I.e., both `NestedApi` and `NestedInternal` can access `inventory.internal.SomethingInventoryInternal`.
|
||||
* Code from nested modules can also access exposed types by top-level application modules.
|
||||
|
||||
Reference in New Issue
Block a user