3
3
import java .lang .reflect .Field ;
4
4
import java .lang .reflect .Member ;
5
5
import java .lang .reflect .Method ;
6
+ import java .util .ArrayDeque ;
6
7
import java .util .ArrayList ;
7
8
import java .util .Collection ;
9
+ import java .util .Deque ;
10
+ import java .util .HashSet ;
8
11
import java .util .List ;
9
12
import java .util .Optional ;
10
13
import java .util .Set ;
13
16
import com .google .common .collect .ImmutableSet ;
14
17
import com .google .common .collect .Sets ;
15
18
import com .societegenerale .commons .plugin .Log ;
19
+ import com .societegenerale .commons .plugin .utils .ReflectionUtils ;
16
20
import com .tngtech .archunit .core .domain .JavaClasses ;
21
+ import com .tngtech .archunit .junit .ArchTests ;
17
22
import com .tngtech .archunit .lang .ArchRule ;
18
23
19
24
import static com .societegenerale .commons .plugin .utils .ReflectionUtils .getValue ;
20
25
import static com .societegenerale .commons .plugin .utils .ReflectionUtils .invoke ;
21
26
import static com .societegenerale .commons .plugin .utils .ReflectionUtils .loadClassWithContextClassLoader ;
22
- import static com .societegenerale .commons .plugin .utils .ReflectionUtils .newInstance ;
23
27
import static java .lang .System .lineSeparator ;
24
28
import static java .util .Arrays .stream ;
25
29
import static java .util .stream .Collectors .joining ;
26
30
import static java .util .stream .Collectors .toSet ;
27
31
28
32
class InvokableRules {
29
- private final Class <?> rulesLocation ;
30
33
private final Set <Field > archRuleFields ;
31
34
private final Set <Method > archRuleMethods ;
32
35
@@ -36,11 +39,17 @@ private InvokableRules(String rulesClassName, List<String> ruleChecks, Log log)
36
39
37
40
this .log =log ;
38
41
39
- rulesLocation = loadClassWithContextClassLoader (rulesClassName );
42
+ Class <?> definedRulesClass = loadClassWithContextClassLoader (rulesClassName );
40
43
41
- Set <Field > allFieldsWhichAreArchRules = getAllFieldsWhichAreArchRules (rulesLocation .getDeclaredFields ());
42
- Set <Method > allMethodsWhichAreArchRules = getAllMethodsWhichAreArchRules (rulesLocation .getDeclaredMethods ());
43
- validateRuleChecks (Sets .union (allMethodsWhichAreArchRules , allFieldsWhichAreArchRules ), ruleChecks );
44
+ Set <Class <?>> rulesClasses = getAllClassesWhichAreArchTests (definedRulesClass );
45
+ rulesClasses .add (definedRulesClass );
46
+ Set <Field > allFieldsWhichAreArchRules = new HashSet <>();
47
+ Set <Method > allMethodsWhichAreArchRules = new HashSet <>();
48
+ for (Class <?> rulesClass : rulesClasses ) {
49
+ allFieldsWhichAreArchRules .addAll (getAllFieldsWhichAreArchRules (rulesClass .getDeclaredFields ()));
50
+ allMethodsWhichAreArchRules .addAll (getAllMethodsWhichAreArchRules (rulesClass .getDeclaredMethods ()));
51
+ }
52
+ validateRuleChecks (definedRulesClass , Sets .union (allMethodsWhichAreArchRules , allFieldsWhichAreArchRules ), ruleChecks );
44
53
45
54
Predicate <String > isChosenCheck = ruleChecks .isEmpty () ? check -> true : ruleChecks ::contains ;
46
55
@@ -64,7 +73,7 @@ private void logBuiltInvokableRules(String rulesClassName) {
64
73
65
74
}
66
75
67
- private void validateRuleChecks (Set <? extends Member > allFieldsAndMethods , Collection <String > ruleChecks ) {
76
+ private void validateRuleChecks (Class <?> rulesLocation , Set <? extends Member > allFieldsAndMethods , Collection <String > ruleChecks ) {
68
77
Set <String > allFieldAndMethodNames = allFieldsAndMethods .stream ().map (Member ::getName ).collect (toSet ());
69
78
Set <String > illegalChecks = Sets .difference (ImmutableSet .copyOf (ruleChecks ), allFieldAndMethodNames );
70
79
@@ -91,9 +100,26 @@ private Set<Field> getAllFieldsWhichAreArchRules(Field[] fields) {
91
100
.collect (toSet ());
92
101
}
93
102
94
- InvocationResult invokeOn (JavaClasses importedClasses ) {
103
+ private Set <Class <?>> getAllClassesWhichAreArchTests (Class <?> startClass ) {
104
+ Set <Class <?>> allClassesWhichAreArchTests = new HashSet <>();
105
+ Deque <Class <?>> stack = new ArrayDeque <>();
106
+ stack .push (startClass );
107
+ while (!stack .isEmpty ()) {
108
+ Class <?> currentClass = stack .pop ();
109
+ stream (currentClass .getDeclaredFields ())
110
+ .filter (f -> ArchTests .class .isAssignableFrom (f .getType ()))
111
+ .map (f -> getValue (f , null ))
112
+ .map (ArchTests .class ::cast )
113
+ .map (ArchTests ::getDefinitionLocation )
114
+ .forEach (childClass -> {
115
+ allClassesWhichAreArchTests .add (childClass );
116
+ stack .push (childClass );
117
+ });
118
+ }
119
+ return allClassesWhichAreArchTests ;
120
+ }
95
121
96
- Object instance = newInstance ( rulesLocation );
122
+ InvocationResult invokeOn ( JavaClasses importedClasses ) {
97
123
98
124
if (log .isInfoEnabled ()) {
99
125
log .info ("applying rules on " +importedClasses .size ()+" classe(s). To see the details, enable debug logs" );
@@ -105,11 +131,11 @@ InvocationResult invokeOn(JavaClasses importedClasses) {
105
131
106
132
InvocationResult result = new InvocationResult ();
107
133
for (Method method : archRuleMethods ) {
108
- checkForFailure (() -> invoke (method , instance , importedClasses ))
134
+ checkForFailure (() -> invoke (method , null , importedClasses ))
109
135
.ifPresent (result ::add );
110
136
}
111
137
for (Field field : archRuleFields ) {
112
- ArchRule rule = getValue (field , instance );
138
+ ArchRule rule = getValue (field , null );
113
139
checkForFailure (() -> rule .check (importedClasses ))
114
140
.ifPresent (result ::add );
115
141
}
0 commit comments