Fork me on GitHub

进阶注解处理器 processor (三)

序言

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

annotation

1
2
3
4
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface JackLog {
}

processor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
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

1
com.jack.processor.JackLogProcessor

结语

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

-------------本文结束感谢您的阅读-------------
如果您对博主的原创满意,欢迎您继续支持下博主~