Skip to content

Commit 6182fa6

Browse files
committed
#19: align rules and avoid redundancies
commit 7ff3729e4003022aa48a0554215ec4767da7b68f Merge: 3da3b31 ecde7a3 Author: Jörg Hohwiller <[email protected]> Date: Thu Mar 30 19:25:13 2023 +0200 Merge branch 'feature-align-rules-and-avoid-redundancies' of https://github.com/vlad961/archunit into vlad961-feature-align-rules-and-avoid-redundancies # Conflicts: # src/test/java/com/devonfw/sample/archunit/AvoidCyclicDependenciesTest.java # src/test/java/com/devonfw/sample/archunit/ComponentRules.java # src/test/java/com/devonfw/sample/archunit/PackageRule.java # src/test/java/com/devonfw/sample/archunit/ThirdPartyRules.java commit ecde7a3 Author: Vladislav Sehtman <[email protected]> Date: Tue Mar 28 11:21:34 2023 +0200 Rearanged ThirdPartyRules code. commit 74d001e Author: Vladislav Sehtman <[email protected]> Date: Tue Mar 28 11:14:54 2023 +0200 Refactored ThirdPartyRules commit 5f5042a Author: Vladislav Sehtman <[email protected]> Date: Tue Mar 28 10:29:57 2023 +0200 Refactored SecurityRules commit 841616d Author: Vladislav Sehtman <[email protected]> Date: Tue Mar 28 10:24:07 2023 +0200 Refactored PackageRule + renamed LAYER_RULES commit 3a0356e Author: Vladislav Sehtman <[email protected]> Date: Tue Mar 28 10:06:41 2023 +0200 Refactoring NamingConventionRules commit 0b87e4b Author: Vladislav Sehtman <[email protected]> Date: Tue Mar 28 09:37:11 2023 +0200 Refactored LayerRules commit 6f4e70a Merge: 43d2069 1b5ce5b Author: Vladislav Sehtman <[email protected]> Date: Tue Mar 28 09:30:22 2023 +0200 Merge branch 'master' into feature-align-rules-and-avoid-redundancies commit 43d2069 Author: Vladislav Sehtman <[email protected]> Date: Tue Mar 28 09:29:44 2023 +0200 Refactored CyclicDependenciesRules commit 39422df Author: Vladislav Sehtman <[email protected]> Date: Tue Mar 28 09:16:08 2023 +0200 Refactored ComponentRules commit a19b03a Author: Vladislav Sehtman <[email protected]> Date: Fri Mar 24 14:16:38 2023 +0100 removed all tests from distinct files. Combined all tests inside ArchitectureTest.java commit 53d2ea2 Author: Vladislav Sehtman <[email protected]> Date: Fri Mar 24 13:45:33 2023 +0100 First draft of rule alignment - Moved LayerRules into a distinct LayerRulesTest.java file instead of ArchitectureTest.java - Using ArchTests.in() method to gather tests of distinct files.
1 parent 3da3b31 commit 6182fa6

15 files changed

+924
-811
lines changed
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
package com.devonfw.sample.archunit;
2+
3+
import com.tngtech.archunit.base.DescribedPredicate;
4+
import com.tngtech.archunit.core.domain.Dependency;
5+
import com.tngtech.archunit.core.domain.JavaClass;
6+
import com.tngtech.archunit.lang.ArchCondition;
7+
import com.tngtech.archunit.lang.ConditionEvents;
8+
import com.tngtech.archunit.lang.Priority;
9+
import com.tngtech.archunit.lang.SimpleConditionEvent;
10+
import com.tngtech.archunit.lang.syntax.ArchRuleDefinition;
11+
import com.tngtech.archunit.lang.syntax.ArchRuleDefinition.Creator;
12+
13+
/**
14+
* Abstract base class for all topic based collections of rules.
15+
*/
16+
abstract class AbstractRules {
17+
18+
static final String EMBEDDABLE = "Embeddable";
19+
20+
static Creator priority(Priority priority) {
21+
22+
return ArchRuleDefinition.priority(priority);
23+
}
24+
25+
static DescribedPredicate<JavaClass> haveLayer(String layer) {
26+
27+
return new DescribedPredicate<>("in " + layer + " layer") {
28+
@Override
29+
public boolean test(JavaClass type) {
30+
31+
PackageStructure pkg = PackageStructure.of(type);
32+
return pkg.getLayer().equals(layer);
33+
}
34+
};
35+
}
36+
37+
static DescribedPredicate<JavaClass> haveServiceLayer() {
38+
39+
return haveLayer(PackageStructure.LAYER_SERVICE);
40+
}
41+
42+
static DescribedPredicate<JavaClass> haveLogicLayer() {
43+
44+
return haveLayer(PackageStructure.LAYER_LOGIC);
45+
}
46+
47+
static DescribedPredicate<JavaClass> haveDataaccessLayer() {
48+
49+
return haveLayer(PackageStructure.LAYER_DATA_ACCESS);
50+
}
51+
52+
static DescribedPredicate<JavaClass> haveBatchLayer() {
53+
54+
return haveLayer(PackageStructure.LAYER_BATCH);
55+
}
56+
57+
static DescribedPredicate<JavaClass> haveCommonLayer() {
58+
59+
return haveLayer(PackageStructure.LAYER_COMMON);
60+
}
61+
62+
static ArchCondition<JavaClass> dependOnOtherComponentsLayer(String layer) {
63+
64+
return new ArchCondition<>("depend on the " + layer + " layer of a different component") {
65+
@Override
66+
public void check(JavaClass sourceClass, ConditionEvents events) {
67+
68+
PackageStructure sourcePkg = PackageStructure.of(sourceClass);
69+
70+
for (Dependency dependency : sourceClass.getDirectDependenciesFromSelf()) {
71+
72+
JavaClass targetClass = dependency.getTargetClass();
73+
PackageStructure targetPkg = PackageStructure.of(targetClass);
74+
75+
if (targetPkg.isValid() && !sourcePkg.hasSameComponent(targetPkg) && targetPkg.getLayer().equals(layer)
76+
&& (!targetPkg.isComponentGeneral() || !sourcePkg.getLayer().equals(layer))) {
77+
String message = String.format("'%s.%s' depends on '%s.%s' violated in %s by dependency on %s", //
78+
sourcePkg.getComponent(), sourcePkg.getLayer(), //
79+
targetPkg.getComponent(), targetPkg.getLayer(), //
80+
sourceClass.getDescription(), targetClass.getDescription());
81+
events.add(new SimpleConditionEvent(sourceClass, false, message));
82+
}
83+
}
84+
}
85+
};
86+
}
87+
88+
static ArchCondition<JavaClass> dependOnOtherComponentsServiceLayer() {
89+
90+
return dependOnOtherComponentsLayer(PackageStructure.LAYER_SERVICE);
91+
}
92+
93+
static ArchCondition<JavaClass> dependOnOtherComponentsLogicLayer() {
94+
95+
return dependOnOtherComponentsLayer(PackageStructure.LAYER_LOGIC);
96+
}
97+
98+
static ArchCondition<JavaClass> dependOnOtherComponentsDataaccessLayer() {
99+
100+
return dependOnOtherComponentsLayer(PackageStructure.LAYER_DATA_ACCESS);
101+
}
102+
103+
static ArchCondition<JavaClass> dependOnOtherComponentsBatchLayer() {
104+
105+
return dependOnOtherComponentsLayer(PackageStructure.LAYER_BATCH);
106+
}
107+
108+
static ArchCondition<JavaClass> dependOnOtherComponentsCommonLayer() {
109+
110+
return dependOnOtherComponentsLayer(PackageStructure.LAYER_COMMON);
111+
}
112+
113+
static DescribedPredicate<JavaClass> haveComponent(String component) {
114+
115+
return new DescribedPredicate<>("in " + component + " component") {
116+
@Override
117+
public boolean test(JavaClass type) {
118+
119+
PackageStructure pkg = PackageStructure.of(type);
120+
return pkg.getComponent().equals(component);
121+
}
122+
};
123+
}
124+
125+
static DescribedPredicate<JavaClass> notHaveComponent(String component) {
126+
127+
return new DescribedPredicate<>("not in " + component + " component") {
128+
@Override
129+
public boolean test(JavaClass type) {
130+
131+
PackageStructure pkg = PackageStructure.of(type);
132+
return pkg.isValid() && !pkg.getComponent().equals(component);
133+
}
134+
};
135+
}
136+
137+
static DescribedPredicate<JavaClass> haveGeneralComponent() {
138+
139+
return haveComponent(PackageStructure.COMPONENT_GENERAL);
140+
}
141+
142+
static DescribedPredicate<JavaClass> notHaveGeneralComponent() {
143+
144+
return notHaveComponent(PackageStructure.COMPONENT_GENERAL);
145+
}
146+
147+
static ArchCondition<JavaClass> implementEntityInterface(String suffix, String interfaceLayer) {
148+
149+
return new ArchCondition<>("implement an interface with entity name (excluding the " + suffix + " suffix)"
150+
+ ((interfaceLayer == null) ? "" : " in " + interfaceLayer + " layer")) {
151+
@Override
152+
public void check(JavaClass javaClass, ConditionEvents events) {
153+
154+
String expectedSimpleName = javaClass.getSimpleName();
155+
if (expectedSimpleName.endsWith(suffix)) {
156+
expectedSimpleName = expectedSimpleName.substring(0, expectedSimpleName.length() - suffix.length());
157+
} else {
158+
events.add(new SimpleConditionEvent(javaClass, false, javaClass.getFullName() + " does not end with suffix " + suffix));
159+
return;
160+
}
161+
String expectedPackageName;
162+
if (interfaceLayer == null) {
163+
expectedPackageName = javaClass.getPackageName();
164+
} else {
165+
PackageStructure pkg = PackageStructure.of(javaClass).withLayer(interfaceLayer);
166+
expectedPackageName = pkg.getPackage();
167+
}
168+
String expectedInterfaceName = expectedPackageName + "." + expectedSimpleName;
169+
if (!javaClass.getInterfaces().stream().anyMatch(i -> i.getName().equals(expectedInterfaceName))) {
170+
String message = javaClass.getFullName() + " does not implement " + expectedInterfaceName;
171+
events.add(new SimpleConditionEvent(javaClass, false, message));
172+
}
173+
}
174+
};
175+
}
176+
177+
}
Lines changed: 103 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package com.devonfw.sample.archunit;
22

3-
import static com.tngtech.archunit.library.Architectures.layeredArchitecture;
4-
53
import com.tngtech.archunit.core.importer.ImportOption;
64
import com.tngtech.archunit.junit.AnalyzeClasses;
75
import com.tngtech.archunit.junit.ArchTest;
@@ -13,23 +11,109 @@
1311
@AnalyzeClasses(packages = "com.devonfw.sample.archunit", importOptions = ImportOption.DoNotIncludeTests.class)
1412
public class ArchitectureTest {
1513

14+
// Component rules
15+
@ArchTest
16+
private static ArchRule componentsShouldNotHaveCyclicDependencies = ComponentRules.shouldNotHaveCyclicDependencies();
17+
18+
@ArchTest
19+
private static ArchRule serviceLayerShouldNotDependOnServiceLayerOfAnotherComponent = ComponentRules
20+
.serviceLayerShouldNotDependOnServiceLayerOfAnotherComponent();
21+
22+
@ArchTest
23+
private static ArchRule serviceLayerShouldNotDependOnLogicLayerOfAnotherComponent = ComponentRules
24+
.serviceLayerShouldNotDependOnLogicLayerOfAnotherComponent();
25+
26+
@ArchTest
27+
private static ArchRule logicLayerShouldNotDependOnDataaccessLayerOfAnotherComponent = ComponentRules
28+
.logicLayerShouldNotDependOnDataaccessLayerOfAnotherComponent();
29+
30+
@ArchTest
31+
private static ArchRule dataaccessLayerShouldNotDependOnDataaccessLayerOfAnotherComponent = ComponentRules
32+
.dataaccessLayerShouldNotDependOnDataaccessLayerOfAnotherComponent();
33+
34+
@ArchTest
35+
private static ArchRule batchLayerShouldNotDependOnLogicLayerOfAnotherComponent = ComponentRules
36+
.batchLayerShouldNotDependOnLogicLayerOfAnotherComponent();
37+
38+
@ArchTest
39+
private static ArchRule componentGeneralDoesNotDependOnAnotherComponent = ComponentRules.generalDoesNotDependOnAnotherComponent();
40+
41+
// Layer rules
42+
@ArchTest
43+
private static ArchRule layersShouldOnlyHaveValidDependencies = LayerRules.layersShouldOnlyHaveValidDependencies();
44+
45+
// Convention rules
46+
@ArchTest
47+
private static ArchRule compositeTransferObjectsShouldHaveCtoSuffixAndCommonLayer = ConventionRules
48+
.compositeTransferObjectsShouldHaveCtoSuffixAndCommonLayer();
49+
50+
@ArchTest
51+
private static ArchRule entitiesShouldHaveEntitySuffixAndDataaccessLayer = ConventionRules
52+
.entitiesShouldHaveEntitySuffixAndDataaccessLayer();
53+
54+
@ArchTest
55+
private static ArchRule entityTransferObjectsShouldHaveEtoSuffixAndCommonLayerAndImplementEntityInterface = ConventionRules
56+
.entityTransferObjectsShouldHaveEtoSuffixAndCommonLayerAndImplementEntityInterface();
57+
58+
@ArchTest
59+
private static ArchRule useCasesShouldHaveLogicLayer = ConventionRules.useCasesShouldHaveLogicLayer();
60+
61+
@ArchTest
62+
private static ArchRule mappersShouldHaveMapperSuffixAndLogicLayer = ConventionRules.mappersShouldHaveMapperSuffixAndLogicLayer();
63+
64+
@ArchTest
65+
private static ArchRule restServicesShouldHaveServiceSuffixAndServiceLayer = ConventionRules
66+
.restServicesShouldHaveServiceSuffixAndServiceLayer();
67+
68+
@ArchTest
69+
private static ArchRule jpaRepositoriesShouldHaveEntityNamePrefixRepositorySuffixAndDataaccessLayer = ConventionRules
70+
.jpaRepositoriesShouldHaveEntityNamePrefixRepositorySuffixAndDataaccessLayer();
71+
72+
@ArchTest
73+
private static ArchRule useCasesShouldHaveUcPrefix = ConventionRules.useCasesShouldHaveUcPrefix();
74+
75+
@ArchTest
76+
private static ArchRule embeddablesShouldHaveEmbeddableSuffixAndCommonLayer = ConventionRules
77+
.embeddablesShouldHaveEmbeddableSuffixAndCommonLayer();
78+
79+
// Package Rules
80+
@ArchTest
81+
private static ArchRule allPackagesShouldHaveValidStructure = PackageRules.allPackagesShouldHaveValidStructure();
82+
83+
// Security Rules
84+
@ArchTest
85+
private static ArchRule useCaseMethodsShouldBeAnnotatedWithSecurityAnnotation = SecurityRules
86+
.useCaseMethodsShouldBeAnnotatedWithSecurityAnnotation();
87+
88+
@ArchTest
89+
private static ArchRule shouldNotCreateQueryFromString = SecurityRules.shouldNotCreateQueryFromString();
90+
91+
// Third-Party Rules
92+
@ArchTest
93+
private static ArchRule shouldNotUseGuavaObjects = ThirdPartyRules.shouldNotUseGuavaObjects();
94+
95+
@ArchTest
96+
private static ArchRule shouldNotUseJpaConvert = ThirdPartyRules.shouldNotUseJpaConvert();
97+
98+
@ArchTest
99+
private static ArchRule shouldNotUseMysemaDependency = ThirdPartyRules.shouldNotUseMysemaDependency();
100+
101+
@ArchTest
102+
private static ArchRule shouldNotUseSpringTransactional = ThirdPartyRules.shouldNotUseSpringTransactional();
103+
104+
@ArchTest
105+
private static ArchRule shouldNotUseTransactionalInApi = ThirdPartyRules.shouldNotUseTransactionalInApi();
106+
107+
@ArchTest
108+
private static ArchRule shouldUseJpaOnlyInDataaccessOrEmbeddables = ThirdPartyRules.shouldUseJpaOnlyInDataaccessExceptEmbeddables();
109+
110+
@ArchTest
111+
private static ArchRule shouldUseHibernateOnlyInDataaccess = ThirdPartyRules.shouldUseHibernateOnlyInDataaccess();
112+
113+
@ArchTest
114+
private static ArchRule shouldUseJpaInsteadOfHibernate = ThirdPartyRules.shouldUseJpaInsteadOfHibernate();
115+
16116
@ArchTest
17-
private static final ArchRule shouldOnlyAccessValidLayers = //
18-
layeredArchitecture().consideringAllDependencies() //
19-
.layer("common").definedBy("..common..") //
20-
.layer("logic").definedBy("..logic..") //
21-
.layer("dataaccess").definedBy("..dataaccess..") //
22-
.layer("service").definedBy("..service..") //
23-
.layer("client").definedBy("..client..")
24-
.layer("batch").definedBy("..batch..")
25-
26-
.whereLayer("client").mayNotBeAccessedByAnyLayer()
27-
.whereLayer("batch").mayNotBeAccessedByAnyLayer()
28-
.whereLayer("service").mayOnlyBeAccessedByLayers("client")
29-
.whereLayer("logic").mayOnlyBeAccessedByLayers("service", "batch")
30-
.whereLayer("dataaccess").mayOnlyBeAccessedByLayers("logic")
31-
.withOptionalLayers(true)
32-
.because("Dependency of technical layers violates architecture rules.");
33-
// ...
117+
private static ArchRule jpaIsUsedAsEncouraged = ThirdPartyRules.jpaIsUsedAsEncouraged();
34118

35119
}

src/test/java/com/devonfw/sample/archunit/AvoidCyclicDependenciesTest.java

Lines changed: 0 additions & 25 deletions
This file was deleted.

0 commit comments

Comments
 (0)