0
# Visitor Pattern
1
2
JavaParser implements the visitor pattern to provide flexible and efficient traversal of AST nodes. The visitor pattern allows you to define operations on AST nodes without modifying the node classes themselves.
3
4
## Capabilities
5
6
### Generic Visitor Interface
7
8
The GenericVisitor interface allows visitors that return values of type R and accept arguments of type A.
9
10
```java { .api }
11
/**
12
* Generic visitor interface for AST traversal with return values
13
* @param <R> Return type of visit methods
14
* @param <A> Argument type passed to visit methods
15
*/
16
public interface GenericVisitor<R, A> {
17
18
// Compilation unit and imports
19
R visit(CompilationUnit n, A arg);
20
R visit(PackageDeclaration n, A arg);
21
R visit(ImportDeclaration n, A arg);
22
23
// Type declarations
24
R visit(ClassOrInterfaceDeclaration n, A arg);
25
R visit(EnumDeclaration n, A arg);
26
R visit(AnnotationDeclaration n, A arg);
27
R visit(RecordDeclaration n, A arg);
28
29
// Members
30
R visit(MethodDeclaration n, A arg);
31
R visit(ConstructorDeclaration n, A arg);
32
R visit(FieldDeclaration n, A arg);
33
R visit(EnumConstantDeclaration n, A arg);
34
R visit(AnnotationMemberDeclaration n, A arg);
35
R visit(InitializerDeclaration n, A arg);
36
R visit(Parameter n, A arg);
37
38
// Expressions
39
R visit(ArrayAccessExpr n, A arg);
40
R visit(ArrayCreationExpr n, A arg);
41
R visit(ArrayInitializerExpr n, A arg);
42
R visit(AssignExpr n, A arg);
43
R visit(BinaryExpr n, A arg);
44
R visit(BooleanLiteralExpr n, A arg);
45
R visit(CastExpr n, A arg);
46
R visit(CharLiteralExpr n, A arg);
47
R visit(ClassExpr n, A arg);
48
R visit(ConditionalExpr n, A arg);
49
R visit(DoubleLiteralExpr n, A arg);
50
R visit(EnclosedExpr n, A arg);
51
R visit(FieldAccessExpr n, A arg);
52
R visit(InstanceOfExpr n, A arg);
53
R visit(IntegerLiteralExpr n, A arg);
54
R visit(LambdaExpr n, A arg);
55
R visit(LongLiteralExpr n, A arg);
56
R visit(MethodCallExpr n, A arg);
57
R visit(MethodReferenceExpr n, A arg);
58
R visit(NameExpr n, A arg);
59
R visit(NullLiteralExpr n, A arg);
60
R visit(ObjectCreationExpr n, A arg);
61
R visit(StringLiteralExpr n, A arg);
62
R visit(SuperExpr n, A arg);
63
R visit(ThisExpr n, A arg);
64
R visit(UnaryExpr n, A arg);
65
R visit(VariableDeclarationExpr n, A arg);
66
67
// Statements
68
R visit(AssertStmt n, A arg);
69
R visit(BlockStmt n, A arg);
70
R visit(BreakStmt n, A arg);
71
R visit(ContinueStmt n, A arg);
72
R visit(DoStmt n, A arg);
73
R visit(ExpressionStmt n, A arg);
74
R visit(ForEachStmt n, A arg);
75
R visit(ForStmt n, A arg);
76
R visit(IfStmt n, A arg);
77
R visit(LabeledStmt n, A arg);
78
R visit(ReturnStmt n, A arg);
79
R visit(SwitchStmt n, A arg);
80
R visit(SynchronizedStmt n, A arg);
81
R visit(ThrowStmt n, A arg);
82
R visit(TryStmt n, A arg);
83
R visit(WhileStmt n, A arg);
84
85
// Types
86
R visit(ArrayType n, A arg);
87
R visit(ClassOrInterfaceType n, A arg);
88
R visit(IntersectionType n, A arg);
89
R visit(PrimitiveType n, A arg);
90
R visit(TypeParameter n, A arg);
91
R visit(UnionType n, A arg);
92
R visit(VoidType n, A arg);
93
R visit(WildcardType n, A arg);
94
95
// Modern Java language features (Java 9+)
96
R visit(ModuleDeclaration n, A arg);
97
R visit(ModuleExportsDirective n, A arg);
98
R visit(ModuleOpensDirective n, A arg);
99
R visit(ModuleProvidesDirective n, A arg);
100
R visit(ModuleRequiresDirective n, A arg);
101
R visit(ModuleUsesDirective n, A arg);
102
103
// Records (Java 14+)
104
R visit(RecordDeclaration n, A arg);
105
R visit(CompactConstructorDeclaration n, A arg);
106
107
// Pattern matching and newer expressions (Java 14+)
108
R visit(SwitchExpr n, A arg);
109
R visit(YieldStmt n, A arg);
110
R visit(TextBlockLiteralExpr n, A arg);
111
R visit(TypePatternExpr n, A arg);
112
R visit(RecordPatternExpr n, A arg);
113
114
// Additional statement types
115
R visit(LocalClassDeclarationStmt n, A arg);
116
R visit(LocalRecordDeclarationStmt n, A arg);
117
R visit(SwitchEntry n, A arg);
118
R visit(UnparsableStmt n, A arg);
119
120
// Additional type and modifier support
121
R visit(VarType n, A arg);
122
R visit(ReceiverParameter n, A arg);
123
R visit(Modifier n, A arg);
124
R visit(ArrayCreationLevel n, A arg)
125
}
126
```
127
128
### Void Visitor Interface
129
130
The VoidVisitor interface is for visitors that perform side effects without returning values.
131
132
```java { .api }
133
/**
134
* Void visitor interface for AST traversal with side effects only
135
* @param <A> Argument type passed to visit methods
136
*/
137
public interface VoidVisitor<A> {
138
139
// Same visit method signatures as GenericVisitor but returning void
140
void visit(CompilationUnit n, A arg);
141
void visit(ClassOrInterfaceDeclaration n, A arg);
142
void visit(MethodDeclaration n, A arg);
143
void visit(FieldDeclaration n, A arg);
144
// ... all other visit methods returning void
145
}
146
```
147
148
### Visitor Adapter Classes
149
150
JavaParser provides adapter classes that implement default behavior for all visit methods, allowing you to override only the methods you need.
151
152
```java { .api }
153
/**
154
* Adapter providing default implementations for GenericVisitor
155
* @param <R> Return type
156
* @param <A> Argument type
157
*/
158
public abstract class GenericVisitorAdapter<R, A> implements GenericVisitor<R, A> {
159
160
/**
161
* Default visit behavior - visits all child nodes and returns null
162
* Override specific visit methods to provide custom behavior
163
*/
164
// Default implementations for all visit methods...
165
}
166
167
/**
168
* Adapter providing default implementations for VoidVisitor
169
* @param <A> Argument type
170
*/
171
public abstract class VoidVisitorAdapter<A> implements VoidVisitor<A> {
172
173
/**
174
* Default visit behavior - visits all child nodes
175
* Override specific visit methods to provide custom behavior
176
*/
177
// Default implementations for all visit methods...
178
}
179
```
180
181
**Usage Examples:**
182
183
```java
184
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
185
import com.github.javaparser.ast.body.MethodDeclaration;
186
import com.github.javaparser.ast.body.FieldDeclaration;
187
188
// Count methods and fields
189
CompilationUnit cu = StaticJavaParser.parse(code);
190
191
cu.accept(new VoidVisitorAdapter<Void>() {
192
private int methodCount = 0;
193
private int fieldCount = 0;
194
195
@Override
196
public void visit(MethodDeclaration n, Void arg) {
197
methodCount++;
198
System.out.println("Found method: " + n.getNameAsString());
199
super.visit(n, arg); // Continue traversal
200
}
201
202
@Override
203
public void visit(FieldDeclaration n, Void arg) {
204
fieldCount++;
205
n.getVariables().forEach(var ->
206
System.out.println("Found field: " + var.getNameAsString()));
207
super.visit(n, arg);
208
}
209
}, null);
210
```
211
212
### Specialized Visitor Implementations
213
214
JavaParser includes several built-in visitor implementations for common tasks.
215
216
```java { .api }
217
/**
218
* Visitor for modifying AST nodes during traversal
219
* @param <A> Argument type
220
*/
221
public class ModifierVisitor<A> implements GenericVisitor<Visitable, A> {
222
223
/**
224
* Visit and potentially modify nodes
225
* Return the same node to keep it, return a different node to replace it,
226
* return null to remove it
227
*/
228
// Implementation allows modification during traversal
229
}
230
231
/**
232
* Visitor for deep cloning AST nodes
233
*/
234
public class CloneVisitor implements GenericVisitor<Visitable, Object> {
235
236
/**
237
* Creates deep copies of visited nodes
238
* @param n Node to clone
239
* @param arg Clone context
240
* @return Cloned node
241
*/
242
// Implementation for deep cloning
243
}
244
245
/**
246
* Visitor for comparing AST nodes for equality
247
*/
248
public class EqualsVisitor implements GenericVisitor<Boolean, Visitable> {
249
250
/**
251
* Compare two AST nodes for structural equality
252
* @param n First node
253
* @param other Second node to compare against
254
* @return true if nodes are structurally equal
255
*/
256
// Implementation for equality comparison
257
}
258
259
/**
260
* Visitor for computing hash codes of AST nodes
261
*/
262
public class HashCodeVisitor implements GenericVisitor<Integer, Void> {
263
264
/**
265
* Compute hash code for AST node
266
* @param n Node to hash
267
* @param arg Not used
268
* @return Hash code of the node
269
*/
270
// Implementation for hash code computation
271
}
272
```
273
274
**Usage Examples:**
275
276
```java
277
// Clone an AST node
278
Node original = cu.findFirst(ClassOrInterfaceDeclaration.class).get();
279
Node cloned = original.accept(new CloneVisitor(), null);
280
281
// Compare two nodes for equality
282
boolean equal = original.accept(new EqualsVisitor(), cloned);
283
284
// Modify AST during traversal
285
cu.accept(new ModifierVisitor<Void>() {
286
@Override
287
public Visitable visit(MethodDeclaration n, Void arg) {
288
// Make all methods public
289
n.setPublic(true);
290
return super.visit(n, arg);
291
}
292
293
@Override
294
public Visitable visit(FieldDeclaration n, Void arg) {
295
// Remove private fields
296
if (n.isPrivate()) {
297
return null; // Remove this node
298
}
299
return super.visit(n, arg);
300
}
301
}, null);
302
```
303
304
### Custom Visitor Development
305
306
Create custom visitors by extending the adapter classes and overriding specific visit methods.
307
308
```java { .api }
309
/**
310
* Example: Collect all method names in a class
311
*/
312
public class MethodNameCollector extends VoidVisitorAdapter<List<String>> {
313
314
@Override
315
public void visit(MethodDeclaration n, List<String> collector) {
316
collector.add(n.getNameAsString());
317
super.visit(n, collector); // Continue to child nodes
318
}
319
}
320
321
/**
322
* Example: Calculate complexity metrics
323
*/
324
public class ComplexityCalculator extends GenericVisitorAdapter<Integer, Void> {
325
326
@Override
327
public Integer visit(IfStmt n, Void arg) {
328
int complexity = 1; // Base complexity for if statement
329
complexity += visit(n.getThenStmt(), arg);
330
if (n.getElseStmt().isPresent()) {
331
complexity += visit(n.getElseStmt().get(), arg);
332
}
333
return complexity;
334
}
335
336
@Override
337
public Integer visit(ForStmt n, Void arg) {
338
int complexity = 1; // Base complexity for loop
339
complexity += visit(n.getBody(), arg);
340
return complexity;
341
}
342
343
// Override other control flow visit methods...
344
}
345
```
346
347
**Usage Examples:**
348
349
```java
350
// Use custom visitors
351
CompilationUnit cu = StaticJavaParser.parse(code);
352
353
// Collect method names
354
List<String> methodNames = new ArrayList<>();
355
cu.accept(new MethodNameCollector(), methodNames);
356
System.out.println("Methods found: " + methodNames);
357
358
// Calculate complexity
359
Integer complexity = cu.accept(new ComplexityCalculator(), null);
360
System.out.println("Cyclomatic complexity: " + complexity);
361
```
362
363
### Visitor with Context
364
365
Pass context information through visitor traversal using the argument parameter.
366
367
```java { .api }
368
/**
369
* Context class for tracking traversal state
370
*/
371
public class VisitorContext {
372
private String currentClassName;
373
private int depth;
374
private Map<String, Object> properties;
375
376
// Context management methods
377
public void enterClass(String name) { this.currentClassName = name; }
378
public void exitClass() { this.currentClassName = null; }
379
public void incrementDepth() { depth++; }
380
public void decrementDepth() { depth--; }
381
}
382
```
383
384
**Usage Examples:**
385
386
```java
387
// Visitor with context tracking
388
cu.accept(new VoidVisitorAdapter<VisitorContext>() {
389
@Override
390
public void visit(ClassOrInterfaceDeclaration n, VisitorContext ctx) {
391
ctx.enterClass(n.getNameAsString());
392
System.out.println("Entering class: " + n.getNameAsString() +
393
" at depth " + ctx.getDepth());
394
395
super.visit(n, ctx); // Visit children
396
397
ctx.exitClass();
398
System.out.println("Exiting class: " + n.getNameAsString());
399
}
400
401
@Override
402
public void visit(MethodDeclaration n, VisitorContext ctx) {
403
System.out.println("Method " + n.getNameAsString() +
404
" in class " + ctx.getCurrentClassName());
405
super.visit(n, ctx);
406
}
407
}, new VisitorContext());
408
```
409
410
## Visitor Pattern Benefits
411
412
The visitor pattern in JavaParser provides several advantages:
413
414
- **Separation of Concerns**: Analysis logic is separate from AST node structure
415
- **Extensibility**: Add new operations without modifying AST classes
416
- **Type Safety**: Compile-time checking of visitor method signatures
417
- **Performance**: Efficient traversal with minimal overhead
418
- **Flexibility**: Support for both value-returning and side-effect visitors
419
- **Composition**: Easy to combine multiple visitor behaviors