本文主要介绍利用jdk自带的tools.jar库生成常见java语法。使用场景主要是编译时注解,如lombok等,大致原理为在编译的时候插入相应的语句,体现在class文件上会多出相应语句。
以下内容主要是提炼了一下相关的方法,方便用时参考。本文基于jdk1.8都测试成功。
ps:
也在jdk17中调试过,但是未到测试那一步就有一系列其他报错,之后因为时间原因忙其他东西去了。
示例:
public void test() {
// 生成int类型变量myVariable
int myVariable;
}
代码如下:
private JCVariableDecl createStatement() {
JCModifiers modifiers = treeMaker.Modifiers(0);
Name myVariableName = names.fromString("myVariable");
JCExpression variableType = treeMaker.TypeIdent(TypeTag.INT);
return treeMaker.VarDef(modifiers, myVariableName, variableType, null);
}
示例:
public void test() {
// 生成StringBuilder变量
StringBuilder jsonBuilder = new StringBuilder();
}
代码如下:
private JCVariableDecl createStatement() {
JCModifiers variableModifiers = treeMaker.Modifiers(0);
JCExpression variableType = treeMaker.Ident(names.fromString("StringBuilder"));
Name variableName = names.fromString("stringBuilder");
return treeMaker.VarDef(variableModifiers, variableName, variableType, treeMaker.NewClass(null, List.nil(), variableType, List.nil(), null));
}
示例:
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
代码:
/**
* 创建简单日期格式声明
*
* @return {@link JCStatement}
*/
private JCStatement createSimpleDateFormatStatement() {
return treeMaker.VarDef(
treeMaker.Modifiers(0),
names.fromString("simpleDateFormat"),
treeMaker.Ident(names.fromString("SimpleDateFormat")),
treeMaker.NewClass(
null,
List.nil(),
treeMaker.Ident(names.fromString("SimpleDateFormat")),
List.of(treeMaker.Literal("yyyy-MM-dd HH:mm:ss")),
null
)
);
}
示例:
String myVariable = "aa";
代码:
/**
* 创建语句
* String myVariable = "aa";
*
* @return {@link JCVariableDecl}
*/
private JCVariableDecl createStringStatement() {
JCModifiers modifiers = treeMaker.Modifiers(0);
Name myVariableName = names.fromString("myVariable");
JCExpression variableType = treeMaker.Ident(names.fromString("String"));
JCExpression assignmentExpr = treeMaker.Literal(TypeTag.CLASS, "aa");
return treeMaker.VarDef(modifiers, myVariableName, variableType, assignmentExpr);
}
注意:调用变量的方法,必须先定义变量,不然编译报错
示例:
String myVariable1 = simpleDateFormat.format("value");
代码:
/**
* 创建语句
* String myVariable1 = sdf.format(xxxx);;
*
* @return {@link JCVariableDecl}
*/
private JCVariableDecl createVarToVarMethodStatement() {
JCModifiers modifiers = treeMaker.Modifiers(0);
Name myVariableName = names.fromString("myVariable1");
JCExpression variableType = treeMaker.Ident(names.fromString("String"));
// 创建simpleDateFormat.format(date)
JCExpression receiver = treeMaker.Select(
treeMaker.Ident(names.fromString("simpleDateFormat")),
names.fromString("format")
);
JCExpression arg = treeMaker.Literal("value");
JCMethodInvocation printInvocation = treeMaker.Apply(
List.nil(),
receiver,
List.of(arg)
);
return treeMaker.VarDef(modifiers, myVariableName, variableType, printInvocation);
}
示例:
public void test() {
String str = null;
// 给str赋值
str = "aa";
}
代码如下:
public JCStatement createStringStatement() {
Name variableName = names.fromString("str");
JCExpression assignmentExpr = treeMaker.Literal(TypeTag.CLASS, "aa");
return treeMaker.Exec(treeMaker.Assign(treeMaker.Ident(variableName), assignmentExpr));
}
示例:
public class Test {
private int num;
private int value;
public Test(int num, int value) {
this.num = num;
this.value = value;
}
}
代码如下:
private JCMethodDecl makeConstructorMethodDecl() {
// Generate constructor parameters
JCVariableDecl parameter1 = treeMaker.VarDef(
treeMaker.Modifiers(Flags.PARAMETER),
names.fromString("num"),
treeMaker.TypeIdent(TypeTag.INT),
null
);
JCVariableDecl parameter2 = treeMaker.VarDef(
treeMaker.Modifiers(Flags.PARAMETER),
names.fromString("value"),
treeMaker.TypeIdent(TypeTag.INT),
null
);
List<JCVariableDecl> parameters = List.of(parameter1, parameter2);
// Generate constructor body
JCBlock body = treeMaker.Block(0, List.nil());
// Generate field assignments
JCExpressionStatement assignNum = treeMaker.Exec(
treeMaker.Assign(
treeMaker.Select(treeMaker.Ident(names.fromString("this")), names.fromString("num")),
treeMaker.Ident(parameter1.name)
)
);
JCExpressionStatement assignValue = treeMaker.Exec(
treeMaker.Assign(
treeMaker.Select(treeMaker.Ident(names.fromString("this")), names.fromString("value")),
treeMaker.Ident(parameter2.name)
)
);
body.stats = body.stats.append(assignNum).append(assignValue);
// Generate constructor declaration
JCModifiers modifiers = treeMaker.Modifiers(Flags.PUBLIC);
return treeMaker.MethodDef(
modifiers,
names.fromString("" ),
null,
List.nil(),
parameters,
List.nil(),
body,
null
);
}
示例:
public class Test {
private int num;
private int value;
public Test() {
}
public Test(int num, int value) {
this.num = num;
this.value = value;
}
}
代码如下:
private JCMethodDecl makeNoneConstructorMethodDecl() {
JCBlock body = treeMaker.Block(0, List.nil());
// Generate constructor declaration
JCModifiers modifiers = treeMaker.Modifiers(Flags.PUBLIC);
return treeMaker.MethodDef(
modifiers,
names.fromString("" ),
null,
List.nil(),
List.nil(),
List.nil(),
body,
null
);
}
public JCStatement createSysOutStatement() {
Name variableName = names.fromString("str");
JCExpression printlnExpr = treeMaker.Ident(names.fromString("System"));
printlnExpr = treeMaker.Select(printlnExpr, names.fromString("out"));
printlnExpr = treeMaker.Select(printlnExpr, names.fromString("println"));
JCMethodInvocation printlnInvocation = treeMaker.Apply(List.nil(), printlnExpr, List.of(treeMaker.Ident(variableName)));
return treeMaker.Exec(printlnInvocation);
}
private JCExpressionStatement createConstantAppendStatement(String date) {
// 创建dateFormart.format(date)
JCExpression receiver = treeMaker.Select(
treeMaker.Ident(names.fromString("dateFormart")),
names.fromString("format")
);
JCExpression arg = treeMaker.Literal(value);
JCMethodInvocation printInvocation = treeMaker.Apply(
List.nil(),
receiver,
List.of(arg)
);
// 创建语句
return treeMaker.Exec(printInvocation);
}
private JCExpressionStatement createConstantAppendStatement() {
// 创建user.getName()
JCExpression receiver = treeMaker.Select(
treeMaker.Ident(names.fromString("user")),
names.fromString("getName")
);
JCMethodInvocation printInvocation = treeMaker.Apply(
List.nil(),
receiver,
List.nil()
);
// 创建语句
return treeMaker.Exec(printInvocation);
}
private JCExpressionStatement createVarAppendStatement(String date) {
// 创建dateFormart.format(date)
JCExpression receiver = treeMaker.Select(
treeMaker.Ident(names.fromString("dateFormart")),
names.fromString("format")
);
JCExpression arg = treeMaker.Ident(names.fromString(value));
JCMethodInvocation printInvocation = treeMaker.Apply(
List.nil(),
receiver,
List.of(arg)
);
// 创建语句
return treeMaker.Exec(printInvocation);
}
示例:
public void test() {
if (this.name != null) {
System.out.println("hello world");
}
}
代码如下:
public JCStatement createSysOutStatement(String value) {
JCExpression printlnExpr = treeMaker.Ident(names.fromString("System"));
printlnExpr = treeMaker.Select(printlnExpr, names.fromString("out"));
printlnExpr = treeMaker.Select(printlnExpr, names.fromString("println"));
JCMethodInvocation printlnInvocation = treeMaker.Apply(List.nil(), printlnExpr, List.of(treeMaker.Literal(value)));
return treeMaker.Exec(printlnInvocation);
}
private JCStatement createFieldIfNullStatement() {
JCTree.JCExpression condition = treeMaker.Binary(
JCTree.Tag.NE,
treeMaker.Ident(names.fromString("name")),
treeMaker.Literal(TypeTag.BOT, null)
);
ListBuffer<JCTree.JCStatement> statements = new ListBuffer<>();
JCStatement sysOutStatement = createSysOutStatement("hello world");
statements.append(sysOutStatement);
return treeMaker.If(condition, treeMaker.Block(0, statements.toList()), null);
}
示例:
public void test() {
if (this.name != null) {
System.out.println("hello world");
} else {
System.out.println("hello java");
}
}
代码如下:
private JCStatement createFieldIfNullStatement() {
JCTree.JCExpression condition = treeMaker.Binary(
JCTree.Tag.NE,
treeMaker.Ident(names.fromString("name")),
treeMaker.Literal(TypeTag.BOT, null)
);
ListBuffer<JCTree.JCStatement> statements = new ListBuffer<>();
JCStatement sysOutStatement = createSysOutStatement("hello world");
statements.append(sysOutStatement);
ListBuffer<JCTree.JCStatement> elseStatements = new ListBuffer<>();
JCStatement elseStatement = createSysOutStatement("hello java");
elseStatements.append(elseStatement);
return treeMaker.If(condition, treeMaker.Block(0, statements.toList()), treeMaker.Block(0, elseStatements.toList()));
}
/**
* 创建和返回语句块.
* return jsonBuilder.toString();
*
* @return {@link JCStatement}
*/
private JCStatement createBlockWithReturnStatement() {
return treeMaker.Return(treeMaker.Apply(null, treeMaker.Select(treeMaker.Ident(names.fromString("jsonBuilder")), names.fromString("toString")), List.nil()));
}
示例:
public void onParamMethod() {
}
代码如下:
private JCTree.JCMethodDecl makeNoParamMethodDecl() {
// Generate method modifiers
JCModifiers modifiers = treeMaker.Modifiers(Flags.PUBLIC);
// Generate method parameters
List<JCVariableDecl> parameters = List.nil();
// Generate method return type
JCExpression returnType = treeMaker.TypeIdent(TypeTag.VOID);
return treeMaker.MethodDef(
modifiers,
names.fromString("onParamMethod"),
returnType,
List.nil(),
parameters,
List.nil(),
treeMaker.Block(0, List.nil()),
null
);
}
示例:
public void paramMethod(String param) {
}
代码如下:
private JCTree.JCMethodDecl makeMethodDecl() {
// Generate method parameters
JCVariableDecl parameter = treeMaker.VarDef(
treeMaker.Modifiers(Flags.PARAMETER),
names.fromString("param"),
treeMaker.Ident(names.fromString("String")),
null
);
List<JCVariableDecl> parameters = List.of(parameter);
// Generate method body
JCBlock body = treeMaker.Block(0, List.nil());
// Generate method declaration
JCModifiers modifiers = treeMaker.Modifiers(Flags.PUBLIC);
return treeMaker.MethodDef(
modifiers,
names.fromString("paramMethod"),
treeMaker.TypeIdent(TypeTag.VOID),
List.nil(),
parameters,
List.nil(),
body,
null
);
}
示例:
public String paramMethod(String param) {
return "hello world";
}
代码如下:
private JCTree.JCMethodDecl makeMethodDecl() {
// Generate method parameters
JCVariableDecl parameter = treeMaker.VarDef(
treeMaker.Modifiers(Flags.PARAMETER),
names.fromString("param"),
treeMaker.Ident(names.fromString("String")),
null
);
List<JCVariableDecl> parameters = List.of(parameter);
// Generate method body
JCBlock body = treeMaker.Block(0, List.nil());
JCReturn returnStatement = treeMaker.Return(treeMaker.Literal("hello world"));
body.stats = body.stats.append(returnStatement);
// Generate method declaration
JCModifiers modifiers = treeMaker.Modifiers(Flags.PUBLIC);
return treeMaker.MethodDef(
modifiers,
names.fromString("paramMethod"),
treeMaker.Ident(names.fromString("String")),
List.nil(),
parameters,
List.nil(),
body,
null
);
}
示例:
public String dateToString(Date date) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return simpleDateFormat.format(date);
}
代码如下:
private JCTree.JCMethodDecl makeMethodDecl() {
// Generate method parameters
JCVariableDecl parameter = treeMaker.VarDef(
treeMaker.Modifiers(Flags.PARAMETER),
names.fromString("date"),
treeMaker.Ident(names.fromString("Date")),
null
);
List<JCVariableDecl> parameters = List.of(parameter);
// Generate method body
ListBuffer<JCStatement> statements = new ListBuffer<>();
// Generate SimpleDateFormat declaration
JCVariableDecl sdfDeclaration = treeMaker.VarDef(
treeMaker.Modifiers(0),
names.fromString("simpleDateFormat"),
treeMaker.Ident(names.fromString("SimpleDateFormat")),
treeMaker.NewClass(
null,
List.nil(),
treeMaker.Ident(names.fromString("SimpleDateFormat")),
List.of(treeMaker.Literal("yyyy-MM-dd HH:mm:ss")),
null
)
);
statements.append(sdfDeclaration);
// Generate return statement
JCMethodInvocation formatInvocation = treeMaker.Apply(null, treeMaker.Select(treeMaker.Ident(names.fromString("simpleDateFormat")), names.fromString("format")), List.of(treeMaker.Ident(names.fromString("date"))));
JCReturn returnStatement = treeMaker.Return(formatInvocation);
statements.append(returnStatement);
JCBlock body = treeMaker.Block(0, statements.toList());
JCModifiers modifiers = treeMaker.Modifiers(Flags.PUBLIC);
return treeMaker.MethodDef(
modifiers,
names.fromString("dateToString"),
treeMaker.Ident(names.fromString("String")),
List.nil(),
parameters,
List.nil(),
body,
null
);
}
可以参考上面的例子
public JCStatement createSysOutStatement(String value) {
JCExpression printlnExpr = treeMaker.Ident(names.fromString("System"));
printlnExpr = treeMaker.Select(printlnExpr, names.fromString("out"));
printlnExpr = treeMaker.Select(printlnExpr, names.fromString("println"));
JCMethodInvocation printlnInvocation = treeMaker.Apply(List.nil(), printlnExpr, List.of(treeMaker.Literal(value)));
return treeMaker.Exec(printlnInvocation);
}
private void addImport(Element e) {
TreePath treePath = this.trees.getPath(e);
JCTree.JCCompilationUnit jct = (JCTree.JCCompilationUnit) treePath.getCompilationUnit();
java.util.List<JCTree> trees = new ArrayList();
trees.addAll(jct.defs);
java.util.List<JCTree> sourceImportList = new ArrayList();
trees.forEach((tree) -> {
if (tree.getKind().equals(Tree.Kind.IMPORT)) {
sourceImportList.add(tree);
}
});
java.util.List<JCTree.JCImport> needImportList = new ArrayList();
JCTree.JCImport anImport = this.treeMaker.Import(this.memberAccess("java.util.Date"), false);
needImportList.add(anImport);
anImport = this.treeMaker.Import(this.memberAccess("java.text.SimpleDateFormat"), false);
needImportList.add(anImport);
for (int i = 0; i < needImportList.size(); ++i) {
boolean importExist = false;
for (int j = 0; j < sourceImportList.size(); ++j) {
if ((sourceImportList.get(j)).toString().equals((needImportList.get(i)).toString())) {
importExist = true;
}
}
if (!importExist) {
trees.add(0, needImportList.get(i));
}
}
jct.defs = List.from(trees);
}
private JCTree.JCExpression memberAccess(String components) {
String[] componentArray = components.split("\\.");
JCTree.JCExpression expr = this.treeMaker.Ident(names.fromString(componentArray[0]));
for (int i = 1; i < componentArray.length; ++i) {
expr = this.treeMaker.Select(expr, names.fromString(componentArray[i]));
}
return expr;
}