JavaParser

JavaParser is java 1-14 Parser and Abstract Syntax Tree for Java, including preview features to Java 13.

该项目包含一组实现具有高级分析功能的Java 1.0-Java 14 Parser的库。

这包括Java 13的预览功能,以及Java 14的预览功能正在进行中。

学习资料

官方书籍

阅读:https://leanpub.com/javaparservisited/read_full

TODO: 整本书的学习笔记。

入门例子

Sample project with a basic Maven + JavaParser setup

Sample project with basic Maven + JavaSymbolSolver set up

Inspecting an AST

maven 引入

  [xml]
1
2
3
4
5
<dependency> <groupId>com.github.javaparser</groupId> <artifactId>javaparser-symbol-solver-core</artifactId> <version>3.15.21</version> </dependency>

ps: 需要设置 jdk 级别为 1.8

断点

  [java]
1
2
3
4
5
6
7
8
public static void main(String[] args) { // Parse the code you want to inspect: CompilationUnit cu = StaticJavaParser.parse("class X { int x; }"); // Now comes the inspection code: System.out.println(cu); }

我们可以通过断点的方式获取 "class X { int x; }" 的信息。

输出

  [java]
1
2
3
// Now comes the inspection code: YamlPrinter printer = new YamlPrinter(true); System.out.println(printer.output(cu));

直接输出

  [plaintext]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
--- root(Type=CompilationUnit): types: - type(Type=ClassOrInterfaceDeclaration): isInterface: "false" name(Type=SimpleName): identifier: "X" members: - member(Type=FieldDeclaration): variables: - variable(Type=VariableDeclarator): name(Type=SimpleName): identifier: "x" type(Type=PrimitiveType): type: "INT" ...

xml 格式

  [xml]
1
<root type='CompilationUnit'><types><type type='ClassOrInterfaceDeclaration' isInterface='false'><name type='SimpleName' identifier='X'></name><members><member type='FieldDeclaration'><variables><variable type='VariableDeclarator'><name type='SimpleName' identifier='x'></name><type type='PrimitiveType' type='INT'></type></variable></variables></member></members></type></types></root>

修改 class 文件

直接参考 Sample project with a basic Maven + JavaParser setup

maven 引入

  [xml]
1
2
3
4
5
<dependency> <groupId>com.github.javaparser</groupId> <artifactId>javaparser-core</artifactId> <version>3.15.21</version> </dependency>

原始 java 类

ps: 某种角度是为了展现强大,所以代码很冗余,很长。

  [java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
import com.github.javaparser.utils.CodeGenerationUtils; import com.github.javaparser.utils.SourceRoot; public class Blabla { private final void method1013(StreamBuffer buf, int opcode) { if (opcode != 1) { if (opcode != 2) { if (opcode != 4) { do { if (opcode != 5) { if (opcode == 6) ((Class94) this).anInt1477 = buf.readUnsignedShort(); else { if (opcode != 7) { if (opcode != 8) { if (opcode == 11) ((Class94) this).anInt1456 = 1; else if (opcode != 12) { if (opcode != 16) { if (opcode == 23) ((Class94) this).anInt1424 = (buf.readUnsignedShort()); else if (opcode != 24) { if (opcode == 25) ((Class94) this).anInt1487 = (buf.readUnsignedShort()); else if (opcode == 26) anInt1435 = (buf.readUnsignedShort()); else if (opcode < 30 || opcode >= 35) { if (opcode >= 35 && opcode < 40) ((Class94) this).aStringArray1475[-35 + opcode] = (buf.readString()); else if (opcode == 40) { int i_48_ = (buf.readUnsignedByte()); aShortArray1457 = (new short[i_48_]); aShortArray1492 = (new short[i_48_]); for (int i_49_ = 0; i_49_ < i_48_; i_49_++) { aShortArray1457[i_49_] = (short) buf.readUnsignedShort(); aShortArray1492[i_49_] = (short) buf.readUnsignedShort(); } } else if (opcode != 41) { if (opcode == 42) { int i_50_ = (buf.readUnsignedByte()); aByteArray1501 = (new byte[i_50_]); for (int i_51_ = 0; (i_51_ < i_50_); i_51_++) aByteArray1501[i_51_] = (buf.readByte(false)); } else if (opcode != 65) { if (opcode == 78) anInt1479 = (buf.readUnsignedShort()); else if (opcode == 79) anInt1438 = (buf.readUnsignedShort()); else if (opcode != 90) { if (opcode != 91) { if (opcode == 92) anInt1450 = buf.readUnsignedShort(); else if (opcode != 93) { if (opcode != 95) { if (opcode != 96) { if (opcode == 97) ((Class94) this).anInt1474 = buf.readUnsignedShort(); else if (opcode == 98) ((Class94) this).anInt1500 = buf.readUnsignedShort(); else if (opcode < 100 || opcode >= 110) { if (opcode == 110) anInt1423 = buf.readUnsignedShort(); else if (opcode != 111) { if (opcode == 112) anInt1480 = buf.readUnsignedShort(); else if (opcode != 113) { if (opcode == 114) anInt1439 = buf.readByte(false) * 5; else if (opcode == 115) ((Class94) this).anInt1462 = buf.readUnsignedByte(); else if (opcode != 121) { if (opcode != 122) { if (opcode == 125) { anInt1493 = buf.readByte(false) << 2; anInt1465 = buf.readByte(false) << 2; anInt1437 = buf.readByte(false) << 2; } else if (opcode == 126) { anInt1498 = buf.readByte(false) << 2; anInt1470 = buf.readByte(false) << 2; anInt1446 = buf.readByte(false) << 2; } else if (opcode == 127) { ((Class94) this).anInt1455 = buf.readUnsignedByte(); ((Class94) this).anInt1426 = buf.readUnsignedShort(); } else if (opcode != 128) { if (opcode == 129) { ((Class94) this).anInt1433 = buf.readUnsignedByte(); ((Class94) this).anInt1468 = buf.readUnsignedShort(); } else if (opcode == 130) { ((Class94) this).anInt1440 = buf.readUnsignedByte(); ((Class94) this).anInt1483 = buf.readUnsignedShort(); } else if (opcode != 132) { if (opcode == 249) { int i_52_ = buf.readUnsignedByte(); if (((Class94) this).aClass194_1472 == null) { int i_53_ = Class307.calculateSize(i_52_); ((Class94) this).aClass194_1472 = new HashTable(i_53_); } for (int i_54_ = 0; i_54_ < i_52_; i_54_++) { boolean bool = buf.readUnsignedByte() == 1; int i_55_ = buf.method2507(125); Node class279; if (bool) class279 = new StringNode(buf.readString()); else class279 = new IntegerNode(buf.readInt()); ((Class94) this).aClass194_1472.add((long) i_55_, class279); } } } else { int i_56_ = buf.readUnsignedByte(); ((Class94) this).anIntArray1441 = new int[i_56_]; for (int i_57_ = 0; i_56_ > i_57_; i_57_++) ((Class94) this).anIntArray1441[i_57_] = buf.readUnsignedShort(); } } else { ((Class94) this).anInt1442 = buf.readUnsignedByte(); ((Class94) this).anInt1476 = buf.readUnsignedShort(); } } else ((Class94) this).anInt1431 = buf.readUnsignedShort(); } else ((Class94) this).anInt1429 = buf.readUnsignedShort(); } else anInt1458 = buf.readByte(false); } else anInt1503 = buf.readUnsignedShort(); } else { if (((Class94) this).anIntArray1460 == null) { ((Class94) this).anIntArray1460 = new int[10]; ((Class94) this).anIntArray1445 = new int[10]; } ((Class94) this).anIntArray1460[-100 + opcode] = buf.readUnsignedShort(); ((Class94) this).anIntArray1445[opcode - 100] = buf.readUnsignedShort(); } } else ((Class94) this).anInt1443 = buf.readUnsignedByte(); } else ((Class94) this).anInt1494 = buf.readUnsignedShort(); } else anInt1490 = buf.readUnsignedShort(); } else anInt1466 = buf.readUnsignedShort(); } else anInt1454 = (buf.readUnsignedShort()); } else ((Class94) this).aBoolean1463 = true; } else { int i_58_ = (buf.readUnsignedByte()); aShortArray1504 = (new short[i_58_]); aShortArray1488 = (new short[i_58_]); for (int i_59_ = 0; i_59_ < i_58_; i_59_++) { aShortArray1488[i_59_] = (short) buf.readUnsignedShort(); aShortArray1504[i_59_] = (short) buf.readUnsignedShort(); } } } else ((Class94) this).aStringArray1485[opcode + -30] = (buf.readString()); } else anInt1449 = (buf.readUnsignedShort()); } else ((Class94) this).aBoolean1502 = true; } else ((Class94) this).anInt1473 = (buf.readInt()); } else { ((Class94) this).anInt1491 = buf.readUnsignedShort(); if (((Class94) this).anInt1491 > 32767) ((Class94) this).anInt1491 -= 65536; } } else { ((Class94) this).anInt1425 = buf.readUnsignedShort(); if (((Class94) this).anInt1425 <= 32767) break; ((Class94) this).anInt1425 -= 65536; } break; } break; } ((Class94) this).anInt1444 = buf.readUnsignedShort(); } while (false); } else ((Class94) this).anInt1436 = buf.readUnsignedShort(); } else ((Class94) this).aString1434 = buf.readString(); } else anInt1481 = buf.readUnsignedShort(); } }

核心代码

  [java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
import com.github.javaparser.ast.CompilationUnit; import com.github.javaparser.ast.expr.BinaryExpr; import com.github.javaparser.ast.stmt.IfStmt; import com.github.javaparser.ast.stmt.Statement; import com.github.javaparser.ast.visitor.ModifierVisitor; import com.github.javaparser.ast.visitor.Visitable; import com.github.javaparser.utils.CodeGenerationUtils; import com.github.javaparser.utils.Log; import com.github.javaparser.utils.SourceRoot; import java.nio.file.Paths; /** * Some code that uses JavaParser. */ public class LogicPositivizer { public static void main(String[] args) { // JavaParser has a minimal logging class that normally logs nothing. // Let's ask it to write to standard out: Log.setAdapter(new Log.StandardOutStandardErrorAdapter()); // SourceRoot is a tool that read and writes Java files from packages on a certain root directory. // In this case the root directory is found by taking the root from the current Maven module, // with src/main/resources appended. SourceRoot sourceRoot = new SourceRoot(CodeGenerationUtils.mavenModuleRoot(LogicPositivizer.class).resolve("src/main/resources")); // Our sample is in the root of this directory, so no package name. CompilationUnit cu = sourceRoot.parse("", "Blabla.java"); Log.info("Positivizing!"); cu.accept(new ModifierVisitor<Void>() { /** * For every if-statement, see if it has a comparison using "!=". * Change it to "==" and switch the "then" and "else" statements around. */ @Override public Visitable visit(IfStmt n, Void arg) { // Figure out what to get and what to cast simply by looking at the AST in a debugger! n.getCondition().ifBinaryExpr(binaryExpr -> { if (binaryExpr.getOperator() == BinaryExpr.Operator.NOT_EQUALS && n.getElseStmt().isPresent()) { /* It's a good idea to clone nodes that you move around. JavaParser (or you) might get confused about who their parent is! */ Statement thenStmt = n.getThenStmt().clone(); Statement elseStmt = n.getElseStmt().get().clone(); n.setThenStmt(elseStmt); n.setElseStmt(thenStmt); binaryExpr.setOperator(BinaryExpr.Operator.EQUALS); } }); return super.visit(n, arg); } }, null); // This saves all the files we just read to an output directory. sourceRoot.saveAll( // The path of the Maven module/project which contains the LogicPositivizer class. CodeGenerationUtils.mavenModuleRoot(LogicPositivizer.class) // appended with a path to "output" .resolve(Paths.get("output"))); } }

结果

  [java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
import com.github.javaparser.utils.CodeGenerationUtils; import com.github.javaparser.utils.SourceRoot; public class Blabla { private final void method1013(StreamBuffer buf, int opcode) { if (opcode == 1) anInt1481 = buf.readUnsignedShort(); else { if (opcode == 2) ((Class94) this).aString1434 = buf.readString(); else { if (opcode == 4) ((Class94) this).anInt1436 = buf.readUnsignedShort(); else { do { if (opcode != 5) { if (opcode == 6) ((Class94) this).anInt1477 = buf.readUnsignedShort(); else { if (opcode == 7) { ((Class94) this).anInt1425 = buf.readUnsignedShort(); if (((Class94) this).anInt1425 <= 32767) break; ((Class94) this).anInt1425 -= 65536; } else { if (opcode == 8) { ((Class94) this).anInt1491 = buf.readUnsignedShort(); if (((Class94) this).anInt1491 > 32767) ((Class94) this).anInt1491 -= 65536; } else { if (opcode == 11) ((Class94) this).anInt1456 = 1; else if (opcode == 12) ((Class94) this).anInt1473 = (buf.readInt()); else { if (opcode == 16) ((Class94) this).aBoolean1502 = true; else { if (opcode == 23) ((Class94) this).anInt1424 = (buf.readUnsignedShort()); else if (opcode == 24) anInt1449 = (buf.readUnsignedShort()); else { if (opcode == 25) ((Class94) this).anInt1487 = (buf.readUnsignedShort()); else if (opcode == 26) anInt1435 = (buf.readUnsignedShort()); else if (opcode < 30 || opcode >= 35) { if (opcode >= 35 && opcode < 40) ((Class94) this).aStringArray1475[-35 + opcode] = (buf.readString()); else if (opcode == 40) { int i_48_ = (buf.readUnsignedByte()); aShortArray1457 = (new short[i_48_]); aShortArray1492 = (new short[i_48_]); for (int i_49_ = 0; i_49_ < i_48_; i_49_++) { aShortArray1457[i_49_] = (short) buf.readUnsignedShort(); aShortArray1492[i_49_] = (short) buf.readUnsignedShort(); } } else if (opcode == 41) { int i_58_ = (buf.readUnsignedByte()); aShortArray1504 = (new short[i_58_]); aShortArray1488 = (new short[i_58_]); for (int i_59_ = 0; i_59_ < i_58_; i_59_++) { aShortArray1488[i_59_] = (short) buf.readUnsignedShort(); aShortArray1504[i_59_] = (short) buf.readUnsignedShort(); } } else { if (opcode == 42) { int i_50_ = (buf.readUnsignedByte()); aByteArray1501 = (new byte[i_50_]); for (int i_51_ = 0; (i_51_ < i_50_); i_51_++) aByteArray1501[i_51_] = (buf.readByte(false)); } else if (opcode == 65) ((Class94) this).aBoolean1463 = true; else { if (opcode == 78) anInt1479 = (buf.readUnsignedShort()); else if (opcode == 79) anInt1438 = (buf.readUnsignedShort()); else if (opcode == 90) anInt1454 = (buf.readUnsignedShort()); else { if (opcode == 91) anInt1466 = buf.readUnsignedShort(); else { if (opcode == 92) anInt1450 = buf.readUnsignedShort(); else if (opcode == 93) anInt1490 = buf.readUnsignedShort(); else { if (opcode == 95) ((Class94) this).anInt1494 = buf.readUnsignedShort(); else { if (opcode == 96) ((Class94) this).anInt1443 = buf.readUnsignedByte(); else { if (opcode == 97) ((Class94) this).anInt1474 = buf.readUnsignedShort(); else if (opcode == 98) ((Class94) this).anInt1500 = buf.readUnsignedShort(); else if (opcode < 100 || opcode >= 110) { if (opcode == 110) anInt1423 = buf.readUnsignedShort(); else if (opcode == 111) anInt1503 = buf.readUnsignedShort(); else { if (opcode == 112) anInt1480 = buf.readUnsignedShort(); else if (opcode == 113) anInt1458 = buf.readByte(false); else { if (opcode == 114) anInt1439 = buf.readByte(false) * 5; else if (opcode == 115) ((Class94) this).anInt1462 = buf.readUnsignedByte(); else if (opcode == 121) ((Class94) this).anInt1429 = buf.readUnsignedShort(); else { if (opcode == 122) ((Class94) this).anInt1431 = buf.readUnsignedShort(); else { if (opcode == 125) { anInt1493 = buf.readByte(false) << 2; anInt1465 = buf.readByte(false) << 2; anInt1437 = buf.readByte(false) << 2; } else if (opcode == 126) { anInt1498 = buf.readByte(false) << 2; anInt1470 = buf.readByte(false) << 2; anInt1446 = buf.readByte(false) << 2; } else if (opcode == 127) { ((Class94) this).anInt1455 = buf.readUnsignedByte(); ((Class94) this).anInt1426 = buf.readUnsignedShort(); } else if (opcode == 128) { ((Class94) this).anInt1442 = buf.readUnsignedByte(); ((Class94) this).anInt1476 = buf.readUnsignedShort(); } else { if (opcode == 129) { ((Class94) this).anInt1433 = buf.readUnsignedByte(); ((Class94) this).anInt1468 = buf.readUnsignedShort(); } else if (opcode == 130) { ((Class94) this).anInt1440 = buf.readUnsignedByte(); ((Class94) this).anInt1483 = buf.readUnsignedShort(); } else if (opcode == 132) { int i_56_ = buf.readUnsignedByte(); ((Class94) this).anIntArray1441 = new int[i_56_]; for (int i_57_ = 0; i_56_ > i_57_; i_57_++) ((Class94) this).anIntArray1441[i_57_] = buf.readUnsignedShort(); } else { if (opcode == 249) { int i_52_ = buf.readUnsignedByte(); if (((Class94) this).aClass194_1472 == null) { int i_53_ = Class307.calculateSize(i_52_); ((Class94) this).aClass194_1472 = new HashTable(i_53_); } for (int i_54_ = 0; i_54_ < i_52_; i_54_++) { boolean bool = buf.readUnsignedByte() == 1; int i_55_ = buf.method2507(125); Node class279; if (bool) class279 = new StringNode(buf.readString()); else class279 = new IntegerNode(buf.readInt()); ((Class94) this).aClass194_1472.add((long) i_55_, class279); } } } } } } } } } else { if (((Class94) this).anIntArray1460 == null) { ((Class94) this).anIntArray1460 = new int[10]; ((Class94) this).anIntArray1445 = new int[10]; } ((Class94) this).anIntArray1460[-100 + opcode] = buf.readUnsignedShort(); ((Class94) this).anIntArray1445[opcode - 100] = buf.readUnsignedShort(); } } } } } } } } } else ((Class94) this).aStringArray1485[opcode + -30] = (buf.readString()); } } } } } break; } break; } ((Class94) this).anInt1444 = buf.readUnsignedShort(); } while (false); } } } } }

JavaParser的快速完整API

JavaParser站点的两个API背后的想法迷失在JavaParser网站的黑暗角落。

这是一种尝试:-)

我在这里讨论的API实际上是JavaParser和StaticJavaParser类的API。

快速开始

建立该API的目的是使普通用例尽可能轻松。

最后,此API是完整API的快捷方式的集合。

  [java]
1
2
3
import static com.github.javaparser.StaticJavaParser.*; // ... CompilationUnit cu = parse("class X{}");

StaticJavaParser.parse 处理的是一个完整的 java 文件,你也可以处理一个 File 或者是文件流。

  • 编译表达式
  [java]
1
Expression expression = StaticJavaParser.parseExpression("1+1");

JavaParser api

建立此API的目的是为了获得存在的所有灵活性,并提供更多性能。

  [java]
1
2
3
4
5
6
7
8
import static com.github.javaparser.ParseStart.*; import static com.github.javaparser.Providers.provider; ... JavaParser javaParser = new JavaParser(); ParseResult result = javaParser.parse(COMPILATION_UNIT, provider("class X{}")); result.ifSuccessful(cu -> // use cu );

或者

  [java]
1
2
3
4
5
6
import static com.github.javaparser.ParseStart.*; import static com.github.javaparser.Providers.provider; ... new JavaParser().parse(COMPILATION_UNIT, provider("class X{}")).ifSuccessful(cu -> System.out.println(cu) );

完整的API由JavaParser构造函数和整套解析方法组成,其中有一个额外的功能-一个用于实际解析的功能。

它永远不会引发异常。 ParseResult可以告诉您解析是否正常,如果遇到问题,请告诉我们。

重用JavaParser实例将提高速度。

JavaParser实例不是线程安全的!

extra parse方法的第一个参数指示您将传递的源类型。 通常,它是一个编译单元,但是您可以解析表达式,名称等。

额外解析方法的第二个参数提供源代码。 提供者是对任何种类输入的抽象。

完整的API可让您随意组合这些参数。

再次解析Javadoc是一个例外。 为此,您需要JavadocParser。

可以在构造函数中传递配置。

  [java]
1
2
3
4
5
6
7
8
9
10
11
ParserConfiguration configuration = new ParserConfiguration(); JavaParser parser = new JavaParser(configuration); ParseResult parseResult = parser.parse(EXPRESSION, provider("1+1")); if (!parseResult.isSuccessful()) { System.out.println(parseResult.getProblems().toString()); } // a failed parse does not always mean there is no result. parseResult.getResult().ifPresent(System.out::println); if (parseResult.getCommentsCollection().isPresent()) { // ... }

一次性分析整个项目

JavaParser非常适合分析Java代码,并提供了一种一次性处理源目录的方法。

但是它缺少分析项目的方法,该项目可能包含多个源目录。

以前的答案是手动创建所有SourceRoot,然后可以对其进行分析。

让我们回顾一下JavaParser存储库的以下示例。

为了解析存储库中的所有文件,您必须手动定义每个模块的根目录,然后使用每个源根目录创建SourceRoot,然后可以对其进行进一步处理。

  [java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Path projectRoot = path-to-project-root; String[] roots = new String[]{ "javaparser-core/src/main/java", "javaparser-core-testing/src/test/java", "javaparser-core-generators/src/main/java", "javaparser-core-metamodel-generator/src/main/java", "javaparser-symbol-solver-core/src/main/java", "javaparser-symbol-solver-logic/src/main/java", "javaparser-symbol-solver-model/src/main/java", "javaparser-symbol-solver-testing/src/test/java" }; for (String root : roots) { SourceRoot sourceRoot = new SourceRoot(projectRoot.resolve(root)); List<ParseResult> parseResults = sourceRoot.tryToParse(); }

我们需要一种自动实现此目的的方法,从而避免了所有人重新发明轮子的麻烦。

为此,我们介绍ProjectRootand CollectionStrategy。

如果仅需要解析Java文件,则仅收集项目中的SourceRoots就足够了。

但是,如果您还想解析java文件中的符号,则还需要收集jar文件。

使用ParserCollectionStrategy或SymbolSolverCollectionStrategy,您可以分别指定要解析还是解析。

以下示例显示如何初始化ProjectRoot:

  [java]
1
2
3
4
5
6
7
8
// only parsing private final ProjectRoot projectRoot = new ParserCollectionStrategy() .collect(root); // parsing and resolving private final ProjectRoot projectRoot = new SymbolSolverCollectionStrategy() .collect(root);

拓展阅读

ASM

java assist

cglib

java 源码

java poet

参考资料

基于AST抽象语法树实现删除java/android代码中的Log.*输出,主要运用在apk发布阶段

解析表达式抽象语法树