jdk自带的com.sun.tools库的常见用法

jdk自带的com.sun.tools库的常见用法

本文主要介绍利用jdk自带的tools.jar库生成常见java语法。使用场景主要是编译时注解,如lombok等,大致原理为在编译的时候插入相应的语句,体现在class文件上会多出相应语句。
以下内容主要是提炼了一下相关的方法,方便用时参考。本文基于jdk1.8都测试成功。
ps:
也在jdk17中调试过,但是未到测试那一步就有一系列其他报错,之后因为时间原因忙其他东西去了。

1.定义变量

1.1、在方法内部定义变量,不含初始化(int myVariable;)

示例:

    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);
    }

1.2、在方法内部定义变量,包含初始值(StringBuilder jsonBuilder = new StringBuilder();)

示例:

		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));
    }

1.3、SimpleDateFormat simpleDateFormat = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”);

示例:

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
            )
    );
}

1.4、生成String myVariable = “aa”;

示例:

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);
}

1.5、生成String myVariable1 = simpleDateFormat.format(“value”);

注意:调用变量的方法,必须先定义变量,不然编译报错

示例:

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);
}

2.变量赋值

示例:

    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));
    }

3.有参构造函数

示例:

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
        );
    }

4.无参构造函数

示例:

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
    );
}

5.调用对象方法(有参、无参两种), 包括System.out.println(str), dateFormart.format(date),user.getName()

5.1、输出System.out.println(str)

    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);
    }

5.2、输出dateFormart.format(“date”)

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);
}

5.3、输出user.getName()

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);
}

5.4、输出输出dateFormart.format(date)

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);
}

6.if 语句

示例:

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);
    }

7.else 语句

示例:

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()));
}

8.定义返回对象

/**
 * 创建和返回语句块.
* 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())); }

9.定义方法签名

9.1、定义一个void无参方法

示例:

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
    );
}

9.2、定义一个void有参方法

示例:

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
    );
}

9.3、定义一个string出参方法

示例:

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
    );
}

9.4、定义一个date转string方法

示例:

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
    );
}

10.定义方法体

可以参考上面的例子

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);
}

11.import语句

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;
}

你可能感兴趣的:(java,java)