0
# Java-Only Rules
1
2
Utility methods that provide Java-only equivalents of standard ArchUnit rule definitions. Essential for mixed Java/Scala projects where ArchUnit's limited Scala support can cause analysis issues.
3
4
## Capabilities
5
6
### Java-Only Class Selection
7
8
Provides equivalent functionality to ArchUnit's standard rule definitions but restricted to Java classes only.
9
10
```java { .api }
11
/**
12
* Equivalent of ArchRuleDefinition.classes(), but only for Java classes
13
* @return ClassesThat builder for creating rules that apply only to Java classes
14
*/
15
public static ClassesThat<GivenClassesConjunction> javaClassesThat();
16
17
/**
18
* Equivalent of ArchRuleDefinition.classes() with predicate, but only for Java classes
19
* @param predicate Additional predicate to filter Java classes
20
* @return GivenClassesConjunction for building rules on filtered Java classes
21
*/
22
public static GivenClassesConjunction javaClassesThat(DescribedPredicate<JavaClass> predicate);
23
```
24
25
**Usage Examples:**
26
27
```java
28
import org.apache.flink.architecture.common.GivenJavaClasses;
29
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes;
30
31
// Standard ArchUnit - may include Scala classes
32
ArchRule standardRule = classes()
33
.that().arePublic()
34
.should().haveSimpleNameNotContaining("Impl");
35
36
// Java-only equivalent - excludes Scala classes automatically
37
ArchRule javaOnlyRule = GivenJavaClasses.javaClassesThat()
38
.arePublic()
39
.should().haveSimpleNameNotContaining("Impl");
40
41
// With additional predicate
42
ArchRule serviceClassesRule = GivenJavaClasses.javaClassesThat(
43
clazz -> clazz.getSimpleName().endsWith("Service")
44
).should().notBeInterfaces();
45
```
46
47
### Java-Only Negative Rules
48
49
Provides "no classes" equivalents restricted to Java classes only.
50
51
```java { .api }
52
/**
53
* Equivalent of ArchRuleDefinition.noClasses(), but only for Java classes
54
* @return ClassesThat builder for creating negative rules on Java classes
55
*/
56
public static ClassesThat<GivenClassesConjunction> noJavaClassesThat();
57
58
/**
59
* Equivalent of ArchRuleDefinition.noClasses() with predicate, but only for Java classes
60
* @param predicate Additional predicate to filter Java classes
61
* @return GivenClassesConjunction for building negative rules on filtered Java classes
62
*/
63
public static GivenClassesConjunction noJavaClassesThat(
64
DescribedPredicate<JavaClass> predicate);
65
```
66
67
**Usage Examples:**
68
69
```java
70
// Ensure no Java classes violate naming conventions
71
ArchRule noImplInPublicApi = GivenJavaClasses.noJavaClassesThat()
72
.arePublic()
73
.should().haveSimpleNameContaining("Impl");
74
75
// Ensure no service classes are in wrong package
76
ArchRule noServicesInUtil = GivenJavaClasses.noJavaClassesThat(
77
clazz -> clazz.getSimpleName().endsWith("Service")
78
).should().resideInAPackage("..util..");
79
80
// Complex negative rule
81
ArchRule noPublicInternalClasses = GivenJavaClasses.noJavaClassesThat()
82
.arePublic()
83
.and().resideInAPackage("..internal..")
84
.should().exist();
85
```
86
87
## Java vs Scala Filtering
88
89
### Why Java-Only Rules are Necessary
90
91
```java
92
// Problem: Standard ArchUnit may analyze Scala classes incorrectly
93
ArchRule problematicRule = classes()
94
.that().haveSimpleNameEndingWith("$") // Scala generates $ classes
95
.should().bePackagePrivate(); // May fail on Scala artifacts
96
97
// Solution: Use Java-only rules
98
ArchRule safeRule = GivenJavaClasses.javaClassesThat()
99
.haveSimpleNameNotContaining("$") // No Scala artifacts
100
.should().followCustomNamingConvention();
101
```
102
103
### Integration with SourcePredicates
104
105
```java
106
import org.apache.flink.architecture.common.SourcePredicates;
107
108
// Double-layer protection against non-Java classes
109
ArchRule extraSafeRule = GivenJavaClasses.javaClassesThat(
110
SourcePredicates.areJavaClasses() // Additional Java-only filtering
111
).should().notAccessClassesThat().haveSimpleNameContaining("Scala");
112
```
113
114
## Advanced Usage Patterns
115
116
### Package Structure Validation
117
118
```java
119
// Validate Java package organization
120
ArchRule packageStructureRule = GivenJavaClasses.javaClassesThat()
121
.resideInAPackage("org.apache.flink.api..")
122
.should().onlyAccessClassesThat()
123
.resideInAnyPackage(
124
"org.apache.flink.api..",
125
"org.apache.flink.util..",
126
"java..",
127
"javax.."
128
);
129
130
// Ensure internal packages are not accessed by public API
131
ArchRule internalAccessRule = GivenJavaClasses.noJavaClassesThat()
132
.resideInAPackage("org.apache.flink.api..")
133
.should().accessClassesThat()
134
.resideInAPackage("..internal..");
135
```
136
137
### Class Type Validation
138
139
```java
140
// Validate abstract classes follow conventions
141
ArchRule abstractClassRule = GivenJavaClasses.javaClassesThat()
142
.areAbstract()
143
.and().areNotInterfaces()
144
.should().haveSimpleNameStartingWith("Abstract")
145
.orShould().haveSimpleNameEndingWith("Base");
146
147
// Validate interface naming
148
ArchRule interfaceNamingRule = GivenJavaClasses.javaClassesThat()
149
.areInterfaces()
150
.and().arePublic()
151
.should().haveSimpleNameNotEndingWith("Impl")
152
.andShould().haveSimpleNameNotStartingWith("I");
153
```
154
155
### Annotation-Based Rules
156
157
```java
158
// Validate deprecated classes are properly marked
159
ArchRule deprecatedClassRule = GivenJavaClasses.javaClassesThat()
160
.areAnnotatedWith(Deprecated.class)
161
.should().haveSimpleNameContaining("Deprecated")
162
.orShould().resideInAPackage("..deprecated..");
163
164
// Validate experimental features
165
ArchRule experimentalRule = GivenJavaClasses.javaClassesThat()
166
.areAnnotatedWith("org.apache.flink.annotation.Experimental")
167
.should().resideInAPackage("..experimental..")
168
.orShould().haveSimpleNameContaining("Experimental");
169
```
170
171
### Inheritance and Composition Rules
172
173
```java
174
// Validate service implementation hierarchy
175
ArchRule serviceHierarchyRule = GivenJavaClasses.javaClassesThat()
176
.haveSimpleNameEndingWith("ServiceImpl")
177
.should().implement("org.apache.flink.api.common.Service")
178
.andShould().bePackagePrivate();
179
180
// Validate utility classes are final
181
ArchRule utilityClassRule = GivenJavaClasses.javaClassesThat()
182
.haveSimpleNameEndingWith("Utils")
183
.should().beFinal()
184
.andShould().haveOnlyPrivateConstructors();
185
```
186
187
### Complex Architectural Rules
188
189
```java
190
// Validate layered architecture
191
ArchRule layeredArchitectureRule = GivenJavaClasses.javaClassesThat()
192
.resideInAPackage("..api..")
193
.should().onlyAccessClassesThat()
194
.resideInAnyPackage("..api..", "..spi..", "..util..", "java..")
195
.andShould().notAccessClassesThat()
196
.resideInAnyPackage("..internal..", "..impl..");
197
198
// Validate test utilities don't leak into production
199
ArchRule testUtilityRule = GivenJavaClasses.noJavaClassesThat()
200
.resideOutsideOfPackage("..test..")
201
.should().accessClassesThat()
202
.haveSimpleNameContaining("Test")
203
.orShould().accessClassesThat()
204
.resideInAPackage("..test..");
205
```
206
207
## Performance and Memory Benefits
208
209
### Reduced Analysis Scope
210
211
```java
212
// Memory-intensive: analyzes all classes including Scala artifacts
213
ArchRule memoryHeavyRule = classes()
214
.should().notAccessClassesThat().resideInAPackage("..internal..");
215
216
// Memory-optimized: analyzes only Java classes
217
ArchRule memoryOptimizedRule = GivenJavaClasses.javaClassesThat()
218
.should().notAccessClassesThat().resideInAPackage("..internal..");
219
```
220
221
### Integration with Import Options
222
223
```java
224
import org.apache.flink.architecture.common.ImportOptions;
225
226
// Complete Java-only analysis pipeline
227
JavaClasses javaOnlyClasses = new ClassFileImporter()
228
.withImportOption(new ImportOptions.ExcludeScalaImportOption())
229
.withImportOption(new ImportOptions.ExcludeShadedImportOption())
230
.importPackages("org.apache.flink");
231
232
// Apply Java-only rules to Java-only imports
233
ArchRule completeJavaRule = GivenJavaClasses.javaClassesThat()
234
.arePublic()
235
.should().onlyAccessClassesThat()
236
.areNotAnnotatedWith("org.apache.flink.annotation.Internal");
237
238
completeJavaRule.check(javaOnlyClasses);
239
```
240
241
## Design Principles
242
243
- **Scala Compatibility**: Designed to handle mixed Java/Scala codebases safely
244
- **Drop-in Replacement**: Provides exact equivalents to standard ArchUnit rule definitions
245
- **Performance**: Reduces analysis scope by excluding non-Java classes
246
- **Composability**: Works with all standard ArchUnit conditions and predicates
247
- **Safety**: Provides additional layer of protection against Scala-related analysis issues