<dependency>
+<dependency>
<groupId>com.tngtech.archunit</groupId>
<artifactId>archunit-junit4</artifactId>
- <version>1.2.1</version>
+ <version>1.3.0</version>
<scope>test</scope>
</dependency>
diff --git a/README.md b/README.md
index 28a3baf53..cb9029589 100644
--- a/README.md
+++ b/README.md
@@ -17,7 +17,7 @@ framework.
###### Gradle
```
-testImplementation 'com.tngtech.archunit:archunit:1.2.1'
+testImplementation 'com.tngtech.archunit:archunit:1.3.0'
```
###### Maven
@@ -26,7 +26,7 @@ testImplementation 'com.tngtech.archunit:archunit:1.2.1'
<dependency>
+<dependency>
<groupId>com.tngtech.archunit</groupId>
<artifactId>archunit-junit4</artifactId>
- <version>1.2.1</version>
+ <version>1.3.0</version>
<scope>test</scope>
</dependency>
dependencies {
- testImplementation 'com.tngtech.archunit:archunit-junit4:1.2.1'
+ testImplementation 'com.tngtech.archunit:archunit-junit4:1.3.0'
}
<dependency>
+<dependency>
<groupId>com.tngtech.archunit</groupId>
<artifactId>archunit-junit5</artifactId>
- <version>1.2.1</version>
+ <version>1.3.0</version>
<scope>test</scope>
</dependency>
dependencies {
- testImplementation 'com.tngtech.archunit:archunit-junit5:1.2.1'
+ testImplementation 'com.tngtech.archunit:archunit-junit5:1.3.0'
}
<dependency>
+<dependency>
<groupId>com.tngtech.archunit</groupId>
<artifactId>archunit</artifactId>
- <version>1.2.1</version>
+ <version>1.3.0</version>
<scope>test</scope>
</dependency>
dependencies {
- testImplementation 'com.tngtech.archunit:archunit:1.2.1'
+ testImplementation 'com.tngtech.archunit:archunit:1.3.0'
}
JavaClasses classes = new ClassFileImporter().importPackages("com.mycompany.myapp");
+JavaClasses classes = new ClassFileImporter().importPackages("com.mycompany.myapp");
JavaClasses classes = new ClassFileImporter().importPath("/some/path");
+JavaClasses classes = new ClassFileImporter().importPath("/some/path");
JavaClass clazz = classes.get(Object.class);
+JavaClass clazz = classes.get(Object.class);
System.out.print(clazz.getSimpleName()); // returns 'Object'
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes;
+import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes;
// ...
@@ -762,7 +763,7 @@
-myRule.check(importedClasses);
+myRule.check(importedClasses);
@Test
+@Test
public void Services_should_only_be_accessed_by_Controllers() {
JavaClasses importedClasses = new ClassFileImporter().importPackages("com.mycompany.myapp");
@@ -796,7 +797,7 @@
-@RunWith(ArchUnitRunner.class) // Remove this line for JUnit 5!!
+@RunWith(ArchUnitRunner.class) // Remove this line for JUnit 5!!
@AnalyzeClasses(packages = "com.mycompany.myapp")
public class MyArchitectureTest {
@@ -823,7 +824,7 @@
-@RunWith(ArchUnitRunner::class) // Remove this line for JUnit 5!!
+@RunWith(ArchUnitRunner::class) // Remove this line for JUnit 5!!
@AnalyzeClasses(packagesOf = [MyArchitectureTest::class])
class MyArchitectureTest {
@ArchTest
@@ -850,23 +851,23 @@ 4. What to
4.1. Package Dependency Checks
-
+
-noClasses().that().resideInAPackage("..source..")
+noClasses().that().resideInAPackage("..source..")
.should().dependOnClassesThat().resideInAPackage("..foo..")
-
+
-classes().that().resideInAPackage("..foo..")
+classes().that().resideInAPackage("..foo..")
.should().onlyHaveDependentClassesThat().resideInAnyPackage("..source.one..", "..foo..")
@@ -875,12 +876,12 @@ 4.2. Class Dependency Checks
-
+
-classes().that().haveNameMatching(".*Bar")
+classes().that().haveNameMatching(".*Bar")
.should().onlyHaveDependentClassesThat().haveSimpleName("Bar")
@@ -889,12 +890,12 @@ 4.3. Class and Package Containment Checks
-
+
-classes().that().haveSimpleNameStartingWith("Foo")
+classes().that().haveSimpleNameStartingWith("Foo")
.should().resideInAPackage("com.foo")
@@ -903,23 +904,23 @@ 4.4. Inheritance Checks
-
+
-classes().that().implement(Connection.class)
+classes().that().implement(Connection.class)
.should().haveSimpleNameEndingWith("Connection")
-
+
-classes().that().areAssignableTo(EntityManager.class)
+classes().that().areAssignableTo(EntityManager.class)
.should().onlyHaveDependentClassesThat().resideInAnyPackage("..persistence..")
@@ -928,12 +929,12 @@ 4
4.5. Annotation Checks
-
+
-classes().that().areAssignableTo(EntityManager.class)
+classes().that().areAssignableTo(EntityManager.class)
.should().onlyHaveDependentClassesThat().areAnnotatedWith(Transactional.class)
@@ -942,12 +943,12 @@ 4.5
4.6. Layer Checks
-
+
-layeredArchitecture()
+layeredArchitecture()
.consideringAllDependencies()
.layer("Controller").definedBy("..controller..")
.layer("Service").definedBy("..service..")
@@ -963,12 +964,12 @@ 4.6. Layer Ch
4.7. Cycle Checks
-
+
-slices().matching("com.myapp.(*)..").should().beFreeOfCycles()
+slices().matching("com.myapp.(*)..").should().beFreeOfCycles()
@@ -1003,7 +1004,7 @@ 5.1. Core
-JavaClasses classes = new ClassFileImporter().importPackages("com.mycompany.myapp");
+JavaClasses classes = new ClassFileImporter().importPackages("com.mycompany.myapp");
-ArchRule rule =
+ArchRule rule =
classes().that().resideInAPackage("..service..")
.should().onlyBeAccessed().byAnyPackage("..controller..", "..service..");
@@ -1037,7 +1038,7 @@ 5.2. Lang
-JavaClasses importedClasses = new ClassFileImporter().importPackage("com.myapp");
+JavaClasses importedClasses = new ClassFileImporter().importPackage("com.myapp");
ArchRule rule = // define the rule
rule.check(importedClasses);
@@ -1074,7 +1075,7 @@ 6.1. Import
-JavaClasses classes = new ClassFileImporter().importClasspath();
+JavaClasses classes = new ClassFileImporter().importClasspath();
-JavaClasses classes = new ClassFileImporter().importPath("/some/path/to/classes");
+JavaClasses classes = new ClassFileImporter().importPath("/some/path/to/classes");
-ImportOption ignoreTests = new ImportOption() {
+ImportOption ignoreTests = new ImportOption() {
@Override
public boolean includes(Location location) {
return !location.contains("/test/"); // ignore any URI to sources that contains '/test/'
@@ -1127,7 +1128,7 @@ 6.1. Import
-new ClassFileImporter()
+new ClassFileImporter()
.withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_JARS)
.withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS)
.importClasspath();
@@ -1171,7 +1172,7 @@ 6.2. Domain
-
+
-
+
-
+
-
+
@@ -1259,7 +1260,7 @@
-JavaClasses classes = new ClassFileImporter().importClasspath();
+JavaClasses classes = new ClassFileImporter().importClasspath();
// ArchUnit's java.lang.String
JavaClass javaClass = classes.get(String.class);
@@ -1282,7 +1283,7 @@
-@interface CustomAnnotation {
+@interface CustomAnnotation {
String value();
}
@@ -1292,7 +1293,7 @@
-JavaAnnotation<?> annotation = javaClass.getAnnotationOfType("some.pkg.CustomAnnotation");
+JavaAnnotation<?> annotation = javaClass.getAnnotationOfType("some.pkg.CustomAnnotation");
// result is untyped, since it might not be on the classpath (e.g. enums)
Object value = annotation.get("value");
@@ -1303,7 +1304,7 @@
-CustomAnnotation annotation = javaClass.getAnnotationOfType(CustomAnnotation.class);
+CustomAnnotation annotation = javaClass.getAnnotationOfType(CustomAnnotation.class);
String value = annotation.value();
@@ -1329,7 +1330,7 @@
-Set<JavaClass> services = new HashSet<>();
+Set<JavaClass> services = new HashSet<>();
for (JavaClass clazz : classes) {
// choose those classes with FQN with infix '.service.'
if (clazz.getName().contains(".service.")) {
@@ -1365,7 +1366,7 @@
-ArchRule rule = ArchRuleDefinition.noClasses()
+ArchRule rule = ArchRuleDefinition.noClasses()
.that().resideInAPackage("..service..")
.should().accessClassesThat().resideInAPackage("..controller..");
@@ -1380,7 +1381,7 @@
-java.lang.AssertionError: Architecture Violation [Priority: MEDIUM] -
+java.lang.AssertionError: Architecture Violation [Priority: MEDIUM] -
Rule 'no classes that reside in a package '..service..'
should access classes that reside in a package '..controller..'' was violated (1 times):
Method <some.pkg.service.SomeService.callController()>
@@ -1395,7 +1396,7 @@
-noClasses()
+noClasses()
.that().resideInAPackage("..service..")
.or().resideInAPackage("..persistence..")
.should().accessClassesThat().resideInAPackage("..controller..")
@@ -1415,7 +1416,7 @@
-ArchRule rule = ArchRuleDefinition.methods()
+ArchRule rule = ArchRuleDefinition.methods()
.that().arePublic()
.and().areDeclaredInClassesThat().resideInAPackage("..controller..")
.should().beAnnotatedWith(Secured.class);
@@ -1446,7 +1447,7 @@
-DescribedPredicate<JavaClass> resideInAPackageService = // define the predicate
+DescribedPredicate<JavaClass> resideInAPackageService = // define the predicate
ArchCondition<JavaClass> accessClassesThatResideInAPackageController = // define the condition
noClasses().that(resideInAPackageService)
@@ -1460,7 +1461,7 @@
-DescribedPredicate<JavaClass> haveAFieldAnnotatedWithPayload =
+DescribedPredicate<JavaClass> haveAFieldAnnotatedWithPayload =
new DescribedPredicate<JavaClass>("have a field annotated with @Payload"){
@Override
public boolean test(JavaClass input) {
@@ -1505,7 +1506,7 @@
-JavaClass.Predicates.simpleName(String)
+JavaClass.Predicates.simpleName(String)
@@ -1515,7 +1516,7 @@
-import static com.tngtech.archunit.core.domain.JavaClass.Predicates.assignableTo;
+import static com.tngtech.archunit.core.domain.JavaClass.Predicates.assignableTo;
import static com.tngtech.archunit.core.domain.JavaClass.Predicates.simpleName;
DescribedPredicate<JavaClass> serializableNamedFoo =
@@ -1531,7 +1532,7 @@
-HasName.Predicates.name(String)
+HasName.Predicates.name(String)
@@ -1541,7 +1542,7 @@
-// Does not compile, because type(..) targets a subtype of HasName
+// Does not compile, because type(..) targets a subtype of HasName
HasName.Predicates.name("").and(JavaClass.Predicates.type(Serializable.class))
// Does compile, because name(..) targets a supertype of JavaClass
@@ -1563,7 +1564,7 @@
-ArchCondition<JavaClass> callEquals =
+ArchCondition<JavaClass> callEquals =
ArchConditions.callMethod(Object.class, "equals", Object.class);
ArchCondition<JavaClass> callHashCode =
ArchConditions.callMethod(Object.class, "hashCode");
@@ -1591,7 +1592,7 @@
-
+
@@ -1603,7 +1604,7 @@
-ClassesTransformer<JavaPackage> packages = new AbstractClassesTransformer<JavaPackage>("packages") {
+ClassesTransformer<JavaPackage> packages = new AbstractClassesTransformer<JavaPackage>("packages") {
@Override
public Iterable<JavaPackage> doTransform(JavaClasses classes) {
Set<JavaPackage> result = new HashSet<>();
@@ -1625,7 +1626,7 @@
-// how we map classes to business modules
+// how we map classes to business modules
ClassesTransformer<BusinessModule> businessModules = ...
// filter business module dealing with orders
@@ -1647,7 +1648,7 @@
-classes().that(haveAFieldAnnotatedWithPayload).should(onlyBeAccessedBySecuredMethods)
+classes().that(haveAFieldAnnotatedWithPayload).should(onlyBeAccessedBySecuredMethods)
.because("@Secured methods will be intercepted, checking for increased privileges " +
"and obfuscating sensitive auditing information");
@@ -1659,7 +1660,7 @@
-classes().that(haveAFieldAnnotatedWithPayload).should(onlyBeAccessedBySecuredMethods)
+classes().that(haveAFieldAnnotatedWithPayload).should(onlyBeAccessedBySecuredMethods)
.as("Payload may only be accessed in a secure way");
@@ -1684,7 +1685,7 @@
archunit_ignore_patterns.txt
-.*some\.pkg\.LegacyService.*
+.*some\.pkg\.LegacyService.*
@@ -1697,7 +1698,7 @@
archunit_ignore_patterns.txt
-# There are many known violations where LegacyService is involved; we'll ignore them all
+# There are many known violations where LegacyService is involved; we'll ignore them all
.*some\.pkg\.LegacyService.*
@@ -1719,7 +1720,7 @@ 8.1. Archit
-com.tngtech.archunit.library.Architectures
+com.tngtech.archunit.library.Architectures
-onionArchitecture()
+onionArchitecture()
.domainModels("com.myapp.domain.model..")
.domainServices("com.myapp.domain.service..")
.applicationServices("com.myapp.application..")
@@ -1785,7 +1786,7 @@ 8
-
+
@@ -1798,7 +1799,7 @@ 8.2. Slices
-com.tngtech.archunit.library.dependencies.SlicesRuleDefinition
+com.tngtech.archunit.library.dependencies.SlicesRuleDefinition
-// sort classes by the first package after 'myapp'
+// sort classes by the first package after 'myapp'
// then check those slices for cyclic dependencies
SlicesRuleDefinition.slices().matching("..myapp.(*)..").should().beFreeOfCycles()
@@ -1827,7 +1828,7 @@ 8.2. Slices
-SliceAssignment legacyPackageStructure = new SliceAssignment() {
+SliceAssignment legacyPackageStructure = new SliceAssignment() {
// this will specify which classes belong together in the same slice
@Override
public SliceIdentifier getIdentifierOf(JavaClass javaClass) {
@@ -1885,7 +1886,7 @@
-com.tngtech.archunit.library.cycle_detection.CycleDetector
+com.tngtech.archunit.library.cycle_detection.CycleDetector
@@ -1894,7 +1895,7 @@
-Set<MyNode> nodes = // ...
+Set<MyNode> nodes = // ...
Set<Edge<MyNode>> edges = // ...
Cycles<Edge<MyNode>> foundCycles = CycleDetector.detectCycles(nodes, edges);
@@ -1931,7 +1932,7 @@ <
-ModuleRuleDefinition.modules().definedByPackages("..example.(*)..").should().beFreeOfCycles();
+ModuleRuleDefinition.modules().definedByPackages("..example.(*)..").should().beFreeOfCycles();
@@ -1948,7 +1949,7 @@ <
com/myapp/example/module_one/package-info.java
-@AppModule(
+@AppModule(
name = "Module One",
allowedDependencies = {"Module Two", "Module Three"},
exposedPackages = {"..module_one.api.."}
@@ -1961,7 +1962,7 @@ <
-modules()
+modules()
.definedByAnnotation(AppModule.class)
.should().respectTheirAllowedDependenciesDeclaredIn("allowedDependencies",
consideringOnlyDependenciesInAnyPackage("..example.."))
@@ -1991,7 +1992,7 @@
-ArchModules<?> modules = ArchModules.defineByPackages("..example.(*)..").modularize(javaClasses);
+ArchModules<?> modules = ArchModules.defineByPackages("..example.(*)..").modularize(javaClasses);
ArchModule<?> coreModule = modules.getByIdentifier("core");
Set<? extends ModuleDependency<?>> coreDependencies = coreModule.getModuleDependenciesFromSelf();
coreDependencies.forEach(...);
@@ -2007,7 +2008,7 @@ <
-com.tngtech.archunit.library
+com.tngtech.archunit.library
@@ -2073,7 +2074,7 @@
-com.tngtech.archunit.library.plantuml
+com.tngtech.archunit.library.plantuml
@@ -2082,7 +2083,7 @@
-URL myDiagram = getClass().getResource("my-diagram.puml");
+URL myDiagram = getClass().getResource("my-diagram.puml");
classes().should(adhereToPlantUmlDiagram(myDiagram, consideringAllDependencies()));
@@ -2094,7 +2095,7 @@
-
+
-// considers all dependencies possible (including java.lang, java.util, ...)
+// considers all dependencies possible (including java.lang, java.util, ...)
classes().should(adhereToPlantUmlDiagram(
mydiagram, consideringAllDependencies())
@@ -2140,7 +2141,7 @@ 8.5.1
-// there are further ignore flavors available
+// there are further ignore flavors available
classes().should(adhereToPlantUmlDiagram(mydiagram).ignoreDependencies(predicate))
@@ -2202,7 +2203,7 @@ 8.6.1. Usage
-ArchRule rule = FreezingArchRule.freeze(classes().should()./*complete ArchRule*/);
+ArchRule rule = FreezingArchRule.freeze(classes().should()./*complete ArchRule*/);
-FreezingArchRule.freeze(rule).persistIn(customViolationStore);
+FreezingArchRule.freeze(rule).persistIn(customViolationStore);
@@ -2323,7 +2324,7 @@
-FreezingArchRule.freeze(rule).associateViolationLinesVia(customLineMatcher);
+FreezingArchRule.freeze(rule).associateViolationLinesVia(customLineMatcher);
@@ -2397,7 +2398,7 @@ Example
-
+
-import com.tngtech.archunit.library.metrics.ArchitectureMetrics;
+import com.tngtech.archunit.library.metrics.ArchitectureMetrics;
// ...
JavaClasses classes = // ...
@@ -2482,7 +2483,7 @@ Example
-
+
@@ -2493,7 +2494,7 @@ <
-import com.tngtech.archunit.library.metrics.ArchitectureMetrics;
+import com.tngtech.archunit.library.metrics.ArchitectureMetrics;
// ...
JavaClasses classes = // ...
@@ -2541,7 +2542,7 @@ Example
-
+
@@ -2552,7 +2553,7 @@ <
-import com.tngtech.archunit.library.metrics.ArchitectureMetrics;
+import com.tngtech.archunit.library.metrics.ArchitectureMetrics;
// ...
JavaClasses classes = // ...
@@ -2585,7 +2586,7 @@ 9. JUnit Su
-@Test
+@Test
public void rule1() {
JavaClasses importedClasses = new ClassFileImporter().importClasspath();
@@ -2624,7 +2625,7 @@ 9.1.1. Writ
-@RunWith(ArchUnitRunner.class) // Remove this line for JUnit 5!!
+@RunWith(ArchUnitRunner.class) // Remove this line for JUnit 5!!
@AnalyzeClasses(packages = "com.myapp")
public class ArchitectureTest {
@@ -2662,7 +2663,7 @@
-@AnalyzeClasses(packages = {"com.myapp.subone", "com.myapp.subtwo"})
+@AnalyzeClasses(packages = {"com.myapp.subone", "com.myapp.subtwo"})
@@ -2671,7 +2672,7 @@
-@AnalyzeClasses(packagesOf = {SubOneConfiguration.class, SubTwoConfiguration.class})
+@AnalyzeClasses(packagesOf = {SubOneConfiguration.class, SubTwoConfiguration.class})
@@ -2679,7 +2680,7 @@
-public class MyLocationProvider implements LocationProvider {
+public class MyLocationProvider implements LocationProvider {
@Override
public Set<Location> get(Class<?> testClass) {
// Determine Locations (= URLs) to import
@@ -2697,7 +2698,7 @@
-@AnalyzeClasses(importOptions = {DoNotIncludeTests.class, DoNotIncludeJars.class})
+@AnalyzeClasses(importOptions = {DoNotIncludeTests.class, DoNotIncludeJars.class})
@@ -2722,7 +2723,7 @@
-@AnalyzeClasses(packages = "com.myapp.special", cacheMode = CacheMode.PER_CLASS)
+@AnalyzeClasses(packages = "com.myapp.special", cacheMode = CacheMode.PER_CLASS)
-public class ArchitectureTest {
+public class ArchitectureTest {
// will run
@ArchTest
@@ -2765,7 +2766,7 @@ 9.1.5. Gr
-9.1.6. Generating Display Names
+9.1.6. Executing Single Rules
+
+It is possible to filter specific rules (e.g. @ArchTest
fields) via archunit.properties
(compare Advanced Configuration).
+
+
+archunit.properties
+
+# Specify the field or method name here. Multiple names can be joined by ','
+junit.testFilter=my_custom_rule_field
+
+
+
+As always with archunit.properties
, this can also be passed dynamically using a system property,
+E.g. passing
+
+
+
+-Darchunit.junit.testFilter=my_custom_rule_field
+
+
+
+
+9.1.7. Generating Display Names
ArchUnit offers the possibility to generate more readable names in the test report by replacing underscores in the
original rule names by spaces. For example, if a method or field is named
@@ -2908,7 +2931,7 @@
-com.tngtech.archunit.core.importer.resolvers.ClassResolver
+com.tngtech.archunit.core.importer.resolvers.ClassResolver
@@ -3018,7 +3041,7 @@
-javaClass.getSource().get().getMd5sum()
+javaClass.getSource().get().getMd5sum()
@@ -3031,7 +3054,7 @@
-classes().that().resideInAPackage("com.myapp.old").should()...
+classes().that().resideInAPackage("com.myapp.old").should()...
@@ -3080,7 +3103,7 @@
-com.tngtech.archunit.lang.FailureDisplayFormat
+com.tngtech.archunit.lang.FailureDisplayFormat
@@ -3097,7 +3120,7 @@
-private static class SimpleClassNameFailureFormat implements FailureDisplayFormat {
+private static class SimpleClassNameFailureFormat implements FailureDisplayFormat {
@Override
public String formatFailure(HasDescription rule, FailureMessages failureMessages, Priority priority) {
String failureDetails = failureMessages.stream()
@@ -3121,8 +3144,12 @@
-
-
-
+
+