Closed cdietze closed 4 years ago
Did I understand correctly that you're basically doing the following?
val filteredClasses = importedClasses.that(doNot(equivalentTo(Main::class.java)))
rule.check(filteredClasses)
Restricting importedClasses
after the import does not help in your case because ArchUnit builds the dependencies already during the class file import, as you can see with (I'm switching to Java syntax 😉):
System.out.println(filteredClasses.get(YourAdapter.class).getDirectDependenciesToSelf());
As a temporarily workaround, you might be able to use a tuned ClassFileImporter
to excluding Main
already during import:
new ClassFileImporter().withImportOption(new ImportOption() {
@Override
public boolean includes(Location location) {
return !location.contains(Main.class.getName().replaceAll("\\.", "/"));
}
})
For a proper solution, we should IMO extend OnionArchitecture
to support an ignoreDependency​
mechanism just as LayeredArchitecture
does
Thanks, @hankem.
Your workaround works!
Your suggestion to specify dependencies to ignore on OnionArchitecture
sounds good to me.
Another possibility might be to use https://www.archunit.org/userguide/html/000_Index.html#_ignoring_violations and simply ignore all violations that contain com.myapp.Main
.
But yes, I knew that the need for ignoreDependency
would sooner or later come up :wink:
Please forgive if this is a dumb question, but what is the syntax I need to use .ignoreDependency
for the same case as described by @cdietze? My 'main' class constructs my application – no magic DI frameworks here – and I want to say that it is allowed to depend on anything.
I've tried several variants on
.ignoreDependency("com.mycompany.myapp.ApplicationKt", ".*")
but can't seem to make it work. Help much appreciated!
I get failures such as (somewhat redacted)
Method <com.mycompany.myapp.ApplicationKt.myApp(com.mycompany.myapp.config.AppConfig, com.mycompany.myapp.adapter.repository.SecretsManager)> calls constructor <com.mycompany.myapp.adapter.thirdparty.ThirdPartyConnector.<init>(com.thirdparty.ThirdPartyGateway)> in (Application.kt:53)
@michaelbannister In my project I use:
.ignoreDependency(resideInAPackage("com.example.testproject.test.."), DescribedPredicate.alwaysTrue())
Thank you very much @cdietze, that was enough to get me what I needed!
The string versions of ignoreDependency(..)
actually only take fully qualified class names of origin and target and no wildcards (so they are very specific).
With the predicate version you should be able to cover everything, e.g.
.ignoreDependency(name("com.mycompany.myapp.ApplicationKt"), alwaysTrue())
If you want to very specifically only ignore dependencies from ApplicationKt
to any other class (the resideInAPackage
version of course works, too, as long as you're okay to ignore all dependencies from the whole package).
@michaelbannister In my project I use:
.ignoreDependency(resideInAPackage("com.example.testproject.test.."), DescribedPredicate.alwaysTrue())
Took me a while to figure out how to exclude a test package until I found this post. This works perfectly!
Hello, I tried out the
onionArchitecture()
style on a test project. My test code (Kotlin):I put a main class which bootstraps the application the base package. Now archunit complains that this main class accesses adapter code (which is the case).
I tried to add an exception for that class using:
importedClasses.that(doNot(equivalentTo(Main::class.java)))
but it would still complain that the adapter packages are accessed.Maybe this issue does not occur if I were using DI where the adapter code would not be accessed directly (but actually still are indirectly / at runtime).
What's a good way to solve this? Using a DI-framework should not be mandatory IMO.