进阶注解处理器 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;@Overridepublic 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();}@Overridepublic 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() {@Overridepublic 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.outJCTree.JCFieldAccess s1 = treeMaker.Select(treeMaker.Ident(systemName), outName);// 拼接 System.out.printlnJCTree.JCFieldAccess s2 = treeMaker.Select(s1, printlnName);// 拼接 System.currentTimeMillis()JCTree.JCFieldAccess s3 = treeMaker.Select(treeMaker.Ident(systemName),currentTimeMillisName);// 拼接 System.currentTimeMills() - fStartJCTree.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