前言
环境准备
添加JavaParser依赖
<dependency>
<groupId>com.github.javaparsergroupId>
<artifactId>javaparser-coreartifactId>
<version>3.25.4version>
dependency>
第一个AST解析程序
import com.github.javaparser.StaticJavaParser;
import com.github.javaparser.ast.CompilationUnit;
public class FirstASTDemo {
public static void main(String[] args) {
String code =
"public class HelloWorld {n" +
" public void sayHello() {n" +
" System.out.println("Hello AST!");n" +
" }n" +
"}";
// 解析代码为AST
CompilationUnit cu = StaticJavaParser.parse(code);
// 查看AST结构
System.out.println("=== AST结构 ===");
System.out.println(cu.toString());
}
}
运行这个程序,你会看到完整的AST结构输出。
AST遍历:Visitor模式
理解Visitor设计模式
在AST处理中,Visitor模式让我们能够"访问"每个节点而不修改AST结构。
// 类比:博物馆参观者
public interface ASTVisitor {
void visit(ClassDeclaration node); // 参观"类展区"
void visit(MethodDeclaration node); // 参观"方法展区"
void visit(FieldDeclaration node); // 参观"字段展区"
// ... 其他展区
}
实现自定义Visitor
public class MethodCounter extends VoidVisitorAdapter {
private int methodCount = 0;
@Override
public void visit(MethodDeclaration md, Void arg) {
methodCount++;
System.out.println("发现方法: " + md.getName() +
" (参数: " + md.getParameters().size() + ")");
super.visit(md, arg);
}
public int getMethodCount() {
return methodCount;
}
}
使用这个Visitor:
public class VisitorDemo {
public static void main(String[] args) {
String code =
"public class Calculator {n" +
" public int add(int a, int b) { return a + b; }n" +
" public int multiply(int a, int b) { return a * b; }n" +
"}";
CompilationUnit cu = StaticJavaParser.parse(code);
MethodCounter counter = new MethodCounter();
counter.visit(cu, null);
System.out.println("总方法数: " + counter.getMethodCount());
}
}
输出:
发现方法: add (参数: 2)
发现方法: multiply (参数: 2)
总方法数: 2
常用Visitor场景
收集所有字段信息
public class FieldCollector extends VoidVisitorAdapter {
private List fields = new ArrayList<>();
@Override
public void visit(FieldDeclaration fd, Void arg) {
fd.getVariables().forEach(variable -> {
String fieldInfo = String.format("%s %s %s",
fd.getModifiers(), // 访问修饰符
fd.getElementType(), // 字段类型
variable.getName() // 字段名
);
fields.add(fieldInfo);
});
super.visit(fd, arg);
}
public List getFields() {
return fields;
}
}
查找特定方法调用
public class MethodCallFinder extends VoidVisitorAdapter {
private String targetMethod;
private List calls = new ArrayList<>();
public MethodCallFinder(String targetMethod) {
this.targetMethod = targetMethod;
}
@Override
public void visit(MethodCallExpr n, Void arg) {
if (n.getNameAsString().equals(targetMethod)) {
calls.add("在位置: " + n.getRange().map(r -> r.begin.line).orElse(-1));
}
super.visit(n, arg);
}
}
AST结构可视化:理解AST树
递归打印AST树
import com.github.javaparser.StaticJavaParser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.Node;
public class ASTTreeViewer {
public static void main(String[] args) {
String code =
"public class Calculator {n" +
" private int value;n" +
" n" +
" public int add(int a, int b) {n" +
" return a + b + value;n" +
" }n" +
"}";
CompilationUnit cu = StaticJavaParser.parse(code);
System.out.println("=== AST树状结构 ===");
printASTTree(cu, 0);
}
/**
* 递归打印AST树结构
* @param node 当前节点
* @param depth 当前深度(用于缩进)
*/
public static void printASTTree(Node node, int depth) {
String indent = " ".repeat(depth); // 根据深度生成缩进
String nodeType = node.getClass().getSimpleName();
// 简化的节点内容(避免输出过长)
String content = getNodeSummary(node);
System.out.println(indent + nodeType + ": " + content);
// 递归打印所有子节点
for (Node child : node.getChildNodes()) {
printASTTree(child, depth + 1);
}
}
/**
* 获取节点的简化信息
*/
private static String getNodeSummary(Node node) {
String fullString = node.toString().split("n")[0]; // 取第一行
if (fullString.length() > 50) {
return fullString.substring(0, 47) + "...";
}
return fullString;
}
}
运行结果示例
=== AST树状结构 ===
CompilationUnit: public class Calculator {
ClassOrInterfaceDeclaration: public class Calculator {
Modifier: public
SimpleName: Calculator
FieldDeclaration: private int value;
Modifier: private
VariableDeclarator: value
PrimitiveType: int
SimpleName: value
MethodDeclaration: public int add(int a, int b) {
Modifier: public
SimpleName: add
Parameter: int a
PrimitiveType: int
SimpleName: a
Parameter: int b
PrimitiveType: int
SimpleName: b
PrimitiveType: int
BlockStmt: {
ReturnStmt: return a + b + value;
BinaryExpr: a + b + value
BinaryExpr: a + b
NameExpr: a
SimpleName: a
NameExpr: b
SimpleName: b
NameExpr: value
SimpleName: value
AST树结构解析
树的层次关系
CompilationUnit (根节点 - 整个文件)
└── ClassOrInterfaceDeclaration (类声明)
├── Modifier (修饰符: public)
├── SimpleName (类名: Calculator)
├── FieldDeclaration (字段声明)
│ ├── Modifier (修饰符: private)
│ └── VariableDeclarator (变量声明器)
│ └── SimpleName (字段名: value)
└── MethodDeclaration (方法声明)
├── Modifier (修饰符: public)
├── SimpleName (方法名: add)
├── Parameter (参数)
│ ├── PrimitiveType (类型: int)
│ └── SimpleName (参数名: a)
├── BlockStmt (方法体)
│ └── ReturnStmt (返回语句)
│ └── BinaryExpr (二元表达式: a + b + value)
│ ├── BinaryExpr (子表达式: a + b)
│ │ ├── NameExpr (变量a)
│ │ └── NameExpr (变量b)
│ └── NameExpr (变量value)
关键节点类型说明
| 节点类型 | 说明 | 示例 |
|---|---|---|
CompilationUnit | 整个编译单元 | 整个.java文件 |
ClassOrInterfaceDeclaration | 类或接口声明 | class Calculator |
MethodDeclaration | 方法声明 | public int add(...) |
FieldDeclaration | 字段声明 | private int value |
VariableDeclarator | 变量声明器 | value (字段名) |
BlockStmt | 代码块 | { ... } |
ReturnStmt | 返回语句 | return a + b |
BinaryExpr | 二元表达式 | a + b, x > y |
NameExpr | 名称表达式 | a, b, value |
AST修改:实现代码自动生成
为类添加字段
public class ClassModifier {
public static void addField(CompilationUnit cu,
String fieldName,
String fieldType) {
// 为 user 类添加字段
cu.getClassByName("User").ifPresent(clazz -> {
// 构建字段代码
String fieldCode = "private " + fieldType + " " + fieldName + ";";
// 解析为AST节点并添加
var field = StaticJavaParser.parseBodyDeclaration(fieldCode);
clazz.addMember(field);
System.out.println("成功添加字段: " + fieldName);
});
}
}
自动生成Getter方法
public class GetterGenerator extends VoidVisitorAdapter {
@Override
public void visit(ClassOrInterfaceDeclaration cid, Void arg) {
// 为每个字段生成getter
cid.getFields().forEach(field -> {
field.getVariables().forEach(variable -> {
String fieldName = variable.getNameAsString();
String fieldType = field.getElementType().asString();
generateGetter(cid, fieldName, fieldType);
});
});
super.visit(cid, arg);
}
private void generateGetter(ClassOrInterfaceDeclaration clazz,
String fieldName, String fieldType) {
String getterName = "get" + capitalize(fieldName);
String getterCode = String.format(
"public %s %s() { return this.%s; }",
fieldType, getterName, fieldName
);
try {
var getter = StaticJavaParser.parseBodyDeclaration(getterCode);
clazz.addMember(getter);
System.out.println("生成Getter: " + getterName);
} catch (Exception e) {
System.err.println("生成Getter失败: " + e.getMessage());
}
}
private String capitalize(String str) {
return str.substring(0, 1).toUpperCase() + str.substring(1);
}
}