How to exclude a class in an ArchUnit rule?
Asked Answered
W

3

9

While creating a rule for a layered architecture in ArchUnit, it's not clear to me how to exclude a single class (Main). The base example excludes with a source and a target.

... but I don't get how it converts to my need. I just want just Main to be ignored. Why? Because Main references all layers since it injects all dependencies in place.

The original code is in my GitHub along with the failing test. (the project is a dummy one so it's straightforward to run; just clone it, run the tests and see one failing).

Windhover answered 10/1, 2020 at 8:54 Comment(0)
C
9

Consider you have imported all your classes:

JavaClasses classes = new ClassFileImporter().importPackages("org.example");

Then you typically check all these classes against an ArchRule, no matter if it's a class rule or an architecture rule:

ArchRule rule = classes()
    .that().areAnnotatedWith(Service.class)
    .should().haveSimpleNameEndingWith("Service");

rule.check(classes);

To exclude classes from the rule, you could filter classes and pass the filtered JavaClasses to the rule:

import static com.tngtech.archunit.base.DescribedPredicate.not;
import static com.tngtech.archunit.core.domain.JavaClass.Predicates.equivalentTo;
import static com.tngtech.archunit.lang.conditions.ArchPredicates.are;

JavaClasses allExceptMain = classes.that(are(not(equivalentTo(Main.class))));
rule.check(allExceptMain);

To exclude the class Main and all classes that are defined inside of Main (inner classes, anonymous classes, lambdas etc.) you could adjust the filter:

import static com.tngtech.archunit.base.DescribedPredicate.not;
import static com.tngtech.archunit.core.domain.JavaClass.Predicates.belongToAnyOf;

JavaClasses allExceptMain = classes.that(not(belongToAnyOf(Main.class)));
rule.check(allExceptMain);
Condenser answered 10/1, 2020 at 21:46 Comment(4)
I tried it and it does not work: can you check here please? gist.github.com/lsoares/a3e725a08f185cb1564bdc477c706fd5Benedikta
It looks like the method calls don't happen in users.WebAppConfig directly, but in the class users.WebAppConfig$javalinApp$1$2. (Looks like the class structure generated by Kotlin?) I updated my answer with an example for belongToAnyOf.Condenser
still get this: gist.github.com/lsoares/d98ee5f789a8f75ca3d5210e6ee9967eBenedikta
I edited my question to add the source code if you can take a look that'd be great. the project has no deps. just clone and run the tests. thanksBenedikta
C
2

How about something like this:

.ignoreDependency(fullNameMatching("users.WebAppConfig"), alwaysTrue())
Colver answered 11/1, 2020 at 8:41 Comment(4)
I edited my question to add the source code if you can take a look that'd be great. the project has no deps. just clone and run the tests. thanksBenedikta
I made it work with: .ignoreDependency(fullNameMatching("users.WebAppConfig"), alwaysTrue()) "fullNameMatching" predicate is defined in HasName. You have something similar for types in HasType.Colver
I tried that and it becomes green; problem is that now I can't make it fail in any way.. I tried to break the layer rules and it never becomes red.Benedikta
that's weird, i tried it in one of my projects in java and it worked just fine. maybe it has something to do with the integration with kotlin?Colver
C
0

Another possibility would be to explicitly declare the part of your source code that is in charge of starting the application ("users" package) as a bona fide layer and integrate it into your rules. After all, that's how you want your source code to work, so i wonder if making it an exception is the way to go.

Colver answered 26/1, 2020 at 11:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.