进阶注解处理器 processor (三)

序言

该篇主于实战一个简单的 processor,代码备注很详细,如果对运行和语法还有疑问的请先查阅下前面几篇,重复内容此处就不赘述了~

annotation

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface JackLog {
}

processor

import com.jack.annotation.JackLog;
import com.sun.tools.javac.api.JavacTrees;
import com.sun.tools.javac.model.JavacElements;
import com.sun.tools.javac.processing.JavacProcessingEnvironment;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.tree.TreeTranslator;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.Name;
import com.sun.tools.javac.util.Names;

import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import java.util.Set;

/**
 * @author jack
 */
@SupportedAnnotationTypes("com.jack.annotation.JackLog")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class JackLogProcessor extends AbstractProcessor {

    /**
     * 抽象语法树对象
     */
    private JavacTrees trees;
    /**
     * 用于创建语法树节点的所有方法
     */
    private TreeMaker treeMaker;
    /**
     * 用于创建标识符
     */
    private Names names;
    private JavacElements elementUtils;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        this.trees = JavacTrees.instance(processingEnv);
        Context context = ((JavacProcessingEnvironment) processingEnv).getContext();
        this.treeMaker = TreeMaker.instance(context);
        this.names = Names.instance(context);
        elementUtils = (JavacElements) processingEnv.getElementUtils();
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations,
                           RoundEnvironment roundEnv) {
        Set<? extends Element> set = roundEnv.getElementsAnnotatedWith(JackLog.class);
        set.forEach(element -> {
            JCTree jcTree = trees.getTree(element);
            jcTree.accept(new TreeTranslator() {
                @Override
                public void visitMethodDef(JCTree.JCMethodDecl jcMethodDecl) {
                    doOperationMethod(jcMethodDecl);
                    super.visitMethodDef(jcMethodDecl);
                }
            });
        });
        return true;
    }

    private void doOperationMethod(JCTree.JCMethodDecl jcMethodDecl) {
        treeMaker.pos = jcMethodDecl.pos;
        jcMethodDecl.body = treeMaker.Block(0, List.of(
                getSentenceOne(),
                jcMethodDecl.body,
                getSentenceTwo()
        ));
    }

    private JCTree.JCStatement getSentenceOne() {
        Name systemName = elementUtils.getName("System");
        Name currentTimeMillisName = elementUtils.getName("currentTimeMillis");
        Name longName = elementUtils.getName("Long");
        // 拼接 System.currentTimeMillis()
        JCTree.JCFieldAccess s1 = treeMaker.Select(treeMaker.Ident(systemName),
                currentTimeMillisName);
        treeMaker.Exec(treeMaker.Apply(List.nil(), s1, List.nil()));
        // java.lang.Long fStart = System.currentTimeMillis()
        return treeMaker.VarDef(treeMaker.Modifiers(0),
                names.fromString("fStart"), treeMaker.Ident(longName),
                treeMaker.Apply(List.nil(), s1, List.nil()));
    }

    private JCTree.JCStatement getSentenceTwo() {
        Name systemName = elementUtils.getName("System");
        Name currentTimeMillisName = elementUtils.getName("currentTimeMillis");
        Name outName = elementUtils.getName("out");
        Name printlnName = elementUtils.getName("println");
        // 拼接 System.out
        JCTree.JCFieldAccess s1 = treeMaker.Select(treeMaker.Ident(systemName), outName);
        // 拼接 System.out.println
        JCTree.JCFieldAccess s2 = treeMaker.Select(s1, printlnName);
        // 拼接 System.currentTimeMillis()
        JCTree.JCFieldAccess s3 = treeMaker.Select(treeMaker.Ident(systemName),
                currentTimeMillisName);
        // 拼接 System.currentTimeMills() - fStart
        JCTree.JCBinary s4 = treeMaker.Binary(JCTree.Tag.MINUS,
                treeMaker.Apply(List.nil(), s3, List.nil()),
                treeMaker.Ident(names.fromString("fStart")));
        JCTree.JCBinary s5 = treeMaker.Binary(JCTree.Tag.PLUS,
                treeMaker.Literal("耗时:"), s4);
        JCTree.JCBinary s6 = treeMaker.Binary(JCTree.Tag.PLUS, s5,
                treeMaker.Literal("ms"));
        // System.out.println("耗时:" + (System.currentTimeMills() - fStart) + "ms)
        return treeMaker.Exec(treeMaker.Apply(List.nil(), s2, List.of(s6)));
    }
}

配置文件

javax.annotation.processing.Processor

com.jack.processor.JackLogProcessor

结语

第一个自定义 processor 的实战,后续逐步进阶~

如果您看到了这里,欢迎和我沟通交流!
             一个95后码农

个人博客:fy-blog

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值