0
# Field Analysis
1
2
Specialized predicates focused exclusively on JavaField analysis, providing fine-grained control over field property testing including modifier checking, type validation, and annotation detection.
3
4
## Capabilities
5
6
### Modifier Testing
7
8
Test Java field modifiers for visibility, mutability, and storage characteristics.
9
10
```java { .api }
11
/**
12
* Tests if field has public modifier
13
* @return DescribedPredicate that returns true if field is public
14
*/
15
public static DescribedPredicate<JavaField> isPublic();
16
17
/**
18
* Tests if field has static modifier
19
* @return DescribedPredicate that returns true if field is static
20
*/
21
public static DescribedPredicate<JavaField> isStatic();
22
23
/**
24
* Tests if field does not have static modifier
25
* @return DescribedPredicate that returns true if field is not static (instance field)
26
*/
27
public static DescribedPredicate<JavaField> isNotStatic();
28
29
/**
30
* Tests if field has final modifier
31
* @return DescribedPredicate that returns true if field is final
32
*/
33
public static DescribedPredicate<JavaField> isFinal();
34
```
35
36
**Usage Examples:**
37
38
```java
39
import static org.apache.flink.architecture.common.JavaFieldPredicates.*;
40
41
// Test for public instance fields (usually discouraged)
42
DescribedPredicate<JavaField> publicInstanceField = isPublic().and(isNotStatic());
43
44
// Test for mutable static fields (potential concurrency issues)
45
DescribedPredicate<JavaField> mutableStaticField = isStatic().and(isFinal().negate());
46
47
// Validate constants are properly declared
48
DescribedPredicate<JavaField> properConstant = isPublic().and(isStatic()).and(isFinal());
49
50
ArchRule noPublicInstanceFields = GivenJavaClasses.javaClassesThat()
51
.containAnyFieldsThat(publicInstanceField)
52
.should()
53
.haveSimpleNameEndingWith("DTO");
54
```
55
56
### Type Validation
57
58
Test field types using both Class objects and fully qualified names.
59
60
```java { .api }
61
/**
62
* Tests if field has the specified type using Class object
63
* @param clazz Class type to match exactly
64
* @return DescribedPredicate that returns true if field type matches clazz
65
*/
66
public static DescribedPredicate<JavaField> ofType(Class<?> clazz);
67
68
/**
69
* Tests if field has the specified fully qualified type name
70
* @param fqClassName Fully qualified class name to match
71
* @return DescribedPredicate that returns true if field type name matches fqClassName
72
*/
73
public static DescribedPredicate<JavaField> ofType(String fqClassName);
74
75
/**
76
* Tests if field type is assignable to the given class
77
* @param clazz Class type to check assignability against
78
* @return DescribedPredicate that returns true if field type is assignable to clazz
79
*/
80
public static DescribedPredicate<JavaField> isAssignableTo(Class<?> clazz);
81
```
82
83
**Usage Examples:**
84
85
```java
86
// Check for specific logger type
87
DescribedPredicate<JavaField> isSlf4jLogger = ofType("org.slf4j.Logger");
88
89
// Check for any collection type
90
DescribedPredicate<JavaField> isCollection = isAssignableTo(java.util.Collection.class);
91
92
// Check for String fields specifically
93
DescribedPredicate<JavaField> isStringField = ofType(String.class);
94
95
// Validate logger fields are static final
96
ArchRule loggerFieldsRule = GivenJavaClasses.javaClassesThat()
97
.containAnyFieldsThat(isSlf4jLogger)
98
.should()
99
.onlyHaveFieldsThat(isSlf4jLogger.implies(isStatic().and(isFinal())));
100
```
101
102
### Annotation Detection
103
104
Test for the presence of specific annotations on fields.
105
106
```java { .api }
107
/**
108
* Tests if field is annotated with the specified annotation type
109
* @param annotationType Annotation class to check for
110
* @return DescribedPredicate that returns true if field has the annotation
111
*/
112
public static DescribedPredicate<JavaField> annotatedWith(
113
Class<? extends Annotation> annotationType);
114
115
/**
116
* Tests if field is annotated with annotation specified by fully qualified name
117
* @param fqAnnotationTypeName Fully qualified annotation class name
118
* @return DescribedPredicate that returns true if field has the annotation
119
*/
120
public static DescribedPredicate<JavaField> annotatedWith(String fqAnnotationTypeName);
121
```
122
123
**Usage Examples:**
124
125
```java
126
import javax.annotation.Nullable;
127
import com.fasterxml.jackson.annotation.JsonProperty;
128
129
// Check for nullable fields
130
DescribedPredicate<JavaField> isNullable = annotatedWith(Nullable.class);
131
132
// Check for JSON property fields by fully qualified name
133
DescribedPredicate<JavaField> isJsonProperty =
134
annotatedWith("com.fasterxml.jackson.annotation.JsonProperty");
135
136
// Ensure nullable fields are not primitives
137
ArchRule nullableFieldsRule = GivenJavaClasses.javaClassesThat()
138
.containAnyFieldsThat(isNullable)
139
.should()
140
.onlyHaveFieldsThat(
141
isNullable.implies(
142
ofType("int").negate()
143
.and(ofType("boolean").negate())
144
.and(ofType("double").negate())
145
// ... other primitives
146
)
147
);
148
```
149
150
### Combined Field Validation
151
152
Complex field validation combining multiple criteria.
153
154
**Usage Examples:**
155
156
```java
157
// Validate configuration constants
158
DescribedPredicate<JavaField> isConfigConstant =
159
isPublic()
160
.and(isStatic())
161
.and(isFinal())
162
.and(ofType(String.class))
163
.and(annotatedWith("org.apache.flink.annotation.PublicEvolving"));
164
165
// Validate dependency injection fields
166
DescribedPredicate<JavaField> isInjectedField =
167
isNotStatic()
168
.and(annotatedWith("javax.inject.Inject"))
169
.and(isAssignableTo(Object.class));
170
171
// Validate serialization fields
172
DescribedPredicate<JavaField> isSerialVersionUID =
173
isStatic()
174
.and(isFinal())
175
.and(ofType("long"))
176
.and(field -> field.getName().equals("serialVersionUID"));
177
178
ArchRule configConstantsRule = GivenJavaClasses.javaClassesThat()
179
.haveSimpleNameEndingWith("Config")
180
.should()
181
.onlyHaveFieldsThat(
182
isConfigConstant.or(isSerialVersionUID)
183
);
184
```
185
186
### Predicate Composition Patterns
187
188
Common patterns for combining field predicates effectively.
189
190
**Examples:**
191
192
```java
193
// Logger field validation
194
DescribedPredicate<JavaField> isProperLogger =
195
ofType("org.slf4j.Logger")
196
.and(isStatic())
197
.and(isFinal())
198
.and(field -> field.getName().equals("LOG") || field.getName().equals("LOGGER"));
199
200
// Constant field validation
201
DescribedPredicate<JavaField> isProperConstant =
202
isPublic()
203
.and(isStatic())
204
.and(isFinal())
205
.and(field -> field.getName().equals(field.getName().toUpperCase()));
206
207
// Configuration field validation
208
DescribedPredicate<JavaField> isConfigurationField =
209
isAssignableTo(org.apache.flink.configuration.ConfigOption.class)
210
.and(isStatic())
211
.and(isFinal());
212
213
// Service field validation (dependency injection)
214
DescribedPredicate<JavaField> isServiceField =
215
annotatedWith("org.springframework.beans.factory.annotation.Autowired")
216
.and(isNotStatic())
217
.and(field -> !field.getModifiers().contains(JavaModifier.FINAL));
218
```
219
220
## Design Principles
221
222
- **Fine-Grained Control**: Each predicate focuses on a specific field property for precise architectural rules
223
- **Composability**: All predicates can be combined using `.and()`, `.or()`, and `.negate()` for complex validation
224
- **Type Safety**: Methods use generics and strong typing to ensure compile-time validation
225
- **Circular Dependency Avoidance**: Methods accepting class names recommend using fully qualified strings instead of Class objects
226
- **Performance**: Efficient implementations suitable for analyzing large codebases with many fields