美文网首页
在java文件编译时更改语法树

在java文件编译时更改语法树

作者: 毛不翼 | 来源:发表于2019-10-15 12:09 被阅读0次

添加依赖

<dependency>
      <groupId>com.sun</groupId>
      <artifactId>tools</artifactId>
      <version>1.8</version>
</dependency>

实例代码

@SupportedAnnotationTypes("cn.fireface.call.process.proxy.CallChain")
@SupportedSourceVersion(SourceVersion.RELEASE_7)
public class Process extends AbstractProcessor {
    private Messager messager;
    private JavacTrees trees;
    private TreeMaker treeMaker;
    private Names names;
    Elements elementUtils;

    /** {@inheritDoc} */
    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        System.out.println("init");
        super.init(processingEnv);
        this.messager = processingEnv.getMessager();
        this.trees = JavacTrees.instance(processingEnv);
        Context context = ((JavacProcessingEnvironment) processingEnv).getContext();
        this.treeMaker = TreeMaker.instance(context);
        this.names = Names.instance(context);
        elementUtils = processingEnv.getElementUtils();
    }

    /** {@inheritDoc} */
    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
//        Set<? extends Element> set = roundEnv.getElementsAnnotatedWith(CallChain.class);
        Set<? extends Element> set = roundEnv.getRootElements();
        for (Element element : set) {
            JCTree jcTree = trees.getTree(element);
            if (null==jcTree) {
                continue;
            }
            jcTree.accept(new TreeTranslator() {
                @Override
                public void visitClassDef(JCTree.JCClassDecl jcClassDecl) {
                    List<JCTree.JCVariableDecl> jcVariableDeclList = List.nil();
                    List<JCTree> myDefs = List.nil();
                    for (JCTree tree : jcClassDecl.defs) {
                        if(tree.getKind().equals(Tree.Kind.METHOD)){
                            JCTree.JCMethodDecl jcMethodDecl = (JCTree.JCMethodDecl) tree;
                            if ("<init>".equals(jcMethodDecl.getName().toString()) || "run".equals(jcMethodDecl.getName().toString())){
                                myDefs = myDefs.append(tree);
                                continue;
                            }
                            myDefs = myDefs.append(addCall(jcMethodDecl,jcClassDecl));
                        }else {
                            myDefs=myDefs.append(tree);
                        }
                    }
                    jcClassDecl.defs = myDefs;
                    super.visitClassDef(jcClassDecl);
                }
            });
        }
        return true;
    }

    JCTree.JCStatement execute(JCTree.JCStatement statement, final String key){
        if (!check(statement.getKind())) {
            return statement;
        }
        statement.accept(new JCTree.Visitor() {
            @Override
            public void visitTry(JCTree.JCTry jcTry) {
                JCTree.JCBlock tryBody = jcTry.body;
                jcTry.body = buildNewJcBlock(tryBody, key);
                List<JCTree.JCCatch> catches = jcTry.getCatches();
                for (JCTree.JCCatch aCatch : catches) {
                    JCTree.JCBlock catchBody = aCatch.body;
                    aCatch.body= buildNewJcBlock(catchBody, key);
                }
            }

            @Override
            public void visitIf(JCTree.JCIf jcIf) {
                JCTree.JCStatement thenpart = jcIf.thenpart;
                if (check(thenpart.getKind())) {
                    jcIf.thenpart = execute(thenpart,key);
                }else {
                    JCTree.JCBlock thenBody = (JCTree.JCBlock) thenpart;
                    jcIf.thenpart= buildNewJcBlock(thenBody, key);
                }
                JCTree.JCStatement elseStatement = jcIf.getElseStatement();
                if (elseStatement!=null) {
                    if (check(elseStatement.getKind())) {
                        jcIf.elsepart = execute(elseStatement,key);
                    }else {
                        JCTree.JCBlock elseBody = (JCTree.JCBlock) elseStatement;
                        jcIf.elsepart = buildNewJcBlock(elseBody, key);
                    }
                }
            }


            @Override
            public void visitForLoop(JCTree.JCForLoop jcForLoop) {
                JCTree.JCStatement body = jcForLoop.body;
                if (check(body.getKind())) {
                    jcForLoop.body = execute(body,key);
                }else {
                    JCTree.JCBlock thenBody = (JCTree.JCBlock) body;
                    jcForLoop.body= buildNewJcBlock(thenBody, key);
                }
            }

            @Override
            public void visitForeachLoop(JCTree.JCEnhancedForLoop jcEnhancedForLoop) {
                JCTree.JCStatement body = jcEnhancedForLoop.body;
                if (check(body.getKind())) {
                    jcEnhancedForLoop.body = execute(body,key);
                }else {
                    JCTree.JCBlock thenBody = (JCTree.JCBlock) body;
                    jcEnhancedForLoop.body= buildNewJcBlock(thenBody, key);
                }
            }

            @Override
            public void visitCatch(JCTree.JCCatch jcCatch) {
                JCTree.JCBlock body = jcCatch.body;
                jcCatch.body= buildNewJcBlock(body, key);
            }
        });
        return statement;
    }

    private JCTree.JCBlock buildNewJcBlock(JCTree.JCBlock body, String key) {
        List<JCTree.JCStatement> statements = body.getStatements();

        ListBuffer<JCTree.JCStatement> jcStatements = new ListBuffer<>();

        for (JCTree.JCStatement jcStatement : statements) {
            if (check(jcStatement.getKind())) {
                JCTree.JCStatement execute = execute(jcStatement, key);
                jcStatements=jcStatements.append(execute);
                continue;
            }
            if (jcStatement.getKind()== Tree.Kind.RETURN || jcStatement.getKind()== Tree.Kind.THROW ) {
                JCTree.JCExpressionStatement jcExpressionStatement = buildEndCall(key);
                jcStatements=jcStatements.append(jcExpressionStatement);
            }
            jcStatements=jcStatements.append(jcStatement);
        }
        return treeMaker.Block(0, jcStatements.toList());
    }

    private boolean check(JCTree.Kind kind){
        return kind== Tree.Kind.TRY ||
                kind == Tree.Kind.IF||
                kind == Tree.Kind.FOR_LOOP||
                kind == Tree.Kind.CATCH;
    }




    private JCTree.JCExpressionStatement buildEndCall(String key){
        JCTree.JCFieldAccess selectEnd = treeMaker.Select(treeMaker.Select(treeMaker.Ident(names.fromString("cn.fireface.call.core.utils")), names.fromString("LogPool")), names.fromString("endLog"));
        JCTree.JCMethodInvocation testEnd = treeMaker.Apply(List.<JCTree.JCExpression>nil(), selectEnd, List.<JCTree.JCExpression>of(treeMaker.Literal(key)));
        JCTree.JCExpressionStatement exec = treeMaker.Exec(testEnd);
        return exec;
    }


    private JCTree.JCMethodDecl addCall(JCTree.JCMethodDecl jcMethodDecl,JCTree.JCClassDecl jcClassDecl){

        try {
            String key = getKey(jcMethodDecl, jcClassDecl);

            JCTree.JCBlock body = jcMethodDecl.getBody();
            ListBuffer<JCTree.JCStatement> statementBuffer = new ListBuffer<>();
            JCTree.JCExpressionStatement startCallStatement = buildStartCall(key);
            JCTree.JCExpressionStatement endCallStatement = buildEndCall(key);
            List<JCTree.JCStatement> oldstatements = body.getStatements();
            JCTree returnType = jcMethodDecl.getReturnType();
            if (returnType.type.getKind() == TypeKind.VOID) {

                statementBuffer.append(startCallStatement);
                for (JCTree.JCStatement jcStatement : oldstatements) {
                    if(jcStatement.getKind()== Tree.Kind.RETURN || jcStatement.getKind()== Tree.Kind.THROW){
                        statementBuffer.append(endCallStatement).append(jcStatement);
                        continue;
                    }
                    statementBuffer.append(execute(jcStatement,key));
                }
                if (oldstatements.get(oldstatements.length()-1).getKind() != Tree.
                        Kind.RETURN && oldstatements.get(oldstatements.length()-1).getKind() != Tree.
                        Kind.THROW){
                    statementBuffer.append(endCallStatement);
                }

//                if (oldstatements.get(oldstatements.length()-1).getKind() == Tree.
//                        Kind.THROW) {
//                    statementBuffer.append(startCallStatement).appendArray(oldstatements.subList(0,oldstatements.length()-1).toArray(new JCTree.JCStatement[0])).append(endCallStatement).append(oldstatements.get(oldstatements.length()-1));
//                }else {
//                    statementBuffer.append(startCallStatement).appendArray(oldstatements.toArray(new JCTree.JCStatement[oldstatements.size()])).append(endCallStatement);
//                }
            }else {
                statementBuffer.append(startCallStatement);
                for (JCTree.JCStatement jcStatement : oldstatements) {
                    if(jcStatement.getKind()== Tree.Kind.RETURN || jcStatement.getKind()== Tree.Kind.THROW){
                        statementBuffer.append(endCallStatement).append(jcStatement);
                        continue;
                    }
                    statementBuffer.append(execute(jcStatement,key));
                }
            }
            JCTree.JCBlock body1 = treeMaker.Block(0, statementBuffer.toList());
            return treeMaker.MethodDef(jcMethodDecl.getModifiers(),jcMethodDecl.getName(),jcMethodDecl.restype, jcMethodDecl.getTypeParameters(),jcMethodDecl.getParameters(),jcMethodDecl.getThrows(),body1,jcMethodDecl.defaultValue);
        } catch (Exception e) {
            return jcMethodDecl;
        }
    }

    private String getKey(JCTree.JCMethodDecl jcMethodDecl, JCTree.JCClassDecl jcClassDecl) {
        String classFullName = jcClassDecl.sym.fullname.toString();
        String methodName = jcMethodDecl.getName().toString();
        return classFullName+"."+methodName;
    }

    private JCTree.JCExpressionStatement buildStartCall(String key) {
        JCTree.JCFieldAccess select = treeMaker.Select(treeMaker.Select(treeMaker.Ident(names.fromString("cn.fireface.call.core.utils")), names.fromString("LogPool")), names.fromString("startLog"));
        JCTree.JCMethodInvocation test = treeMaker.Apply(List.<JCTree.JCExpression>nil(), select, List.<JCTree.JCExpression>of(treeMaker.Literal(key)));
        return treeMaker.Exec(test);
    }
}

相关文章

  • 在java文件编译时更改语法树

    添加依赖 实例代码

  • lombok基本使用

    简介### lombok是一个插件,它通过在java编译时修改AST(抽象语法树)以改变字节码文件,来达到某些自定...

  • Java学习笔记(一)编程基础

    1、Java的编译与运行 编译:javac 文件名.java 执行:java 文件名 2、Java语法格式 2.1...

  • 反射

    一、编译时和运行时 编译时:将Java代码编译成.class文件的过程(只涉及纠正语法,不涉及内存运行) ...

  • 类的加载

    可执行程序生成过程 预编译:展开宏,头文件,生成.i文件 编译:生成抽象语法树AST,AST 是抽象语法树,结构上...

  • 8 反射00

    1 编译时 vs 运行时 编译时:将Java代码编译成.class文件的过程【只涉及纠正我们的语法正确与否,不涉及...

  • 使用ASM动态生成class文件

      在java语言中,Java文件在编译时会将java文件编译成.class的字节码文件。通常我们在写代码时只涉及...

  • Java环境变量实例

    Java 实例 - 如何编译 Java 文件 我们在Java基础中已经讲过了如何编译java文件。 javac 命...

  • Caused by: org.hibernate.boot.Ma

    原因是gradle编译时,只复制java文件夹下的.java文件,忽略了XXX.hbm.xml文件,导致在编译输出...

  • AOP面向切面编程

    概念 android中的类都是java文件,系统编译我们写的代码时,会先把java文件编译成.class文件,ao...

网友评论

      本文标题:在java文件编译时更改语法树

      本文链接:https://www.haomeiwen.com/subject/jdtsmctx.html