Issue
I have an @Audit
annotation, it has many optional attributes, I need to enforce the use of one boolean attribute useAccount = true
for certain packages.
I am trying to use archunit to accomplish this validation, that way whenever a developer commits code that breaks the rule the CI will break and inform the team.
This would break the build:
@Audit
public myMethod(...) {
...
}
This is the right way:
@Audit(useAccount = true)
public myMethod(...) {
...
}
The problem is that Archunit doesn't currently support asserting over methods. I was expecting to do something like:
methods().that().resideInAnyPackage("..controllers..", "..service..").and().areAnnotatedWith(Audit.class).should(attributeCheckCondition)
Then my custom condition attributeCheckCondition
would take care of looking into the attribute value.
Is there a way of retrieving methods as we retrieve classes? Without having to write a more complicated predicate and condition?
Solution
Update
Since ArchUnit 0.10.0 it is possible to create rules for members.
methods().that()
.areDeclaredInClassesThat()
.resideInAnyPackage("..controllers..", "..service..")
.and()
.areAnnotatedWith(Audit.class)
.should(attributeCheckCondition)
See also Composing Member Rules in the User Guide.
Original Answer
Since there are currently no basic rule definitions available for methods, an intermediate step is necessary. ArchUnit has a ClassesTransformer
to transform JavaClasses into a collection of other types.
ClassesTransformer<JavaMethod> methods = new AbstractClassesTransformer<JavaMethod>("methods") {
@Override
public Iterable<JavaMethod> doTransform(JavaClasses javaClasses) {
Set<JavaMethod> allMethods = new HashSet<>();
for (JavaClass javaClass : javaClasses) {
allMethods.addAll(javaClass.getMethods());
}
return allMethods;
}
};
This ClassesTransformer
can then be used as a base for custom rule definitions.
ArchRule rule = ArchRuleDefinition.all(methods)
.that(owner(resideInAnyPackage("..controllers..", "..service..")))
.and(annotatedWith(Audit.class))
.should(haveAttributeValue());
rule.check(javaClasses);
See also Rules with Custom Concepts in the User Guide and this issue.
Answered By - Roland Weisleder
Answer Checked By - Candace Johnson (JavaFixing Volunteer)