7

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).

Luís Soares
  • 5,726
  • 4
  • 39
  • 66

3 Answers3

6

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);
Roland Weisleder
  • 9,668
  • 7
  • 37
  • 59
  • I tried it and it does not work: can you check here please? https://gist.github.com/lsoares/a3e725a08f185cb1564bdc477c706fd5 – Luís Soares Jan 10 '20 at 22:11
  • 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`. – Roland Weisleder Jan 11 '20 at 08:47
  • still get this: https://gist.github.com/lsoares/d98ee5f789a8f75ca3d5210e6ee9967e – Luís Soares Jan 11 '20 at 16:35
  • 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. thanks – Luís Soares Jan 11 '20 at 18:44
2

How about something like this:

.ignoreDependency(fullNameMatching("users.WebAppConfig"), alwaysTrue())
  • 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. thanks – Luís Soares Jan 11 '20 at 18:44
  • 1
    I made it work with: .ignoreDependency(fullNameMatching("users.WebAppConfig"), alwaysTrue()) "fullNameMatching" predicate is defined in HasName. You have something similar for types in HasType. – sylvain decout Jan 12 '20 at 19:32
  • 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. – Luís Soares Jan 13 '20 at 00:14
  • 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? – sylvain decout Jan 26 '20 at 11:53
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.