'ArchUnit Rule to prevent access to derived classes?
A colleague did some refactoring and moved a method to a superclass to be able to reuse it from an other child-class, too. The IDE handled that quickly and without any complains. That method, however, internally referred to a constant which was not moved with the method, i.e. the parent class thus now referred to a constant in one of its child-classes which of course is a no-no!
How can I phrase an ArchUnit rule that prevents such references from parent to members/methods/local classes and enums/etc. in child-classes (or in general: anything in classes further down the hierarchy)?
Solution 1:[1]
For direct dependencies, you can use the following custom ArchCondition
:
@ArchTest
ArchRule rule = noClasses().should(new ArchCondition<JavaClass>("depend on their children") {
@Override
public void check(JavaClass parentClass, ConditionEvents events) {
parentClass.getDirectDependenciesFromSelf().stream()
.filter(dependency -> dependency.getTargetClass() != parentClass
&& dependency.getTargetClass().isAssignableTo(parentClass.getName()))
.forEach(dependency -> events.add(satisfied(dependency, dependency.getDescription())));
}
});
It can easily be adapted to also catch transitive dependencies such as in this example:
class Parent {
Friend friend;
}
class Friend {
Child child;
}
class Child extends Parent {
}
You can basically replace getDirectDependenciesFromSelf
with getTransitiveDependenciesFromSelf
:
@ArchTest
ArchRule rule = noClasses().should(new ArchCondition<JavaClass>("depend on their children") {
@Override
public void check(JavaClass parentClass, ConditionEvents events) {
parentClass.getTransitiveDependenciesFromSelf().stream()
.filter(dependency -> dependency.getTargetClass() != parentClass
&& dependency.getTargetClass().isAssignableTo(parentClass.getName()))
.forEach(dependency -> events.add(satisfied(dependency, parentClass.getName()
+ " (transitively) depends on its child: " + dependency.getDescription())));
}
});
FYI: I'm using the following static imports:
import static com.tngtech.archunit.lang.SimpleConditionEvent.satisfied;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Manfred |