思路
上一篇文章的最后有一个@Serial的注解,现在我捋一捋此注解实现的思路。
- 一个项目中有很多很多的类,我们要找出带有@Serial注解的类。然后遍历这些类,对其逐个处理。
- 我们给这个类实现Serializable接口(如果没实现),同时也要把对应的包导入进来。
- 生成一个不重复的long型的值,并赋值给一个叫做serialVersionUID的long型遍历。
- 最后把serialVersionUID加入到类的变量中(如果不存在)。
找出带有指定注解的元素
在JcaProcessor.java
中:1
2
3
4
5
6
7
8
9
10@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) {
// 找出带有@Serial注解的元素
Set<? extends Element> elements = env.getElementsAnnotatedWith(Serial.class);
for (Element element : elements) {
}
return true;
}
每一个Element就是一个带有@Serial注解的类。我想debug看看Element到底是什么鬼,怎么debug呢?编译时注解的debug请见下一篇文章。
给类实现Serializable接口
1 | for (Element element : elements) { |
代码中出现的trees
、treeMaker
和names
,是在JcaProcessor
的init
方法中获取的:1
2
3
4
5
6
7
8
9
10
11
12private Trees trees;
private TreeMaker treeMaker;
private Name.Table names;
@Override
public synchronized void init(ProcessingEnvironment env) {
trees = Trees.instance(env);
Context context = ((JavacProcessingEnvironment) env).getContext();
treeMaker = TreeMaker.instance(context);
names = Names.instance(context).table;
}
其中importPackage
方法的实现如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21/**
* 导入一个包
*
* @param element 所在的类
* @param importClass 要导入的包
*/
private void importPackage(Element element, Class<?> importClass) {
JCTree.JCCompilationUnit compilationUnit = (JCTree.JCCompilationUnit) trees.getPath(element).getCompilationUnit();
JCTree.JCFieldAccess fieldAccess = treeMaker.Select(treeMaker.Ident(names.fromString(importClass.getPackage().getName())), names.fromString(importClass.getSimpleName()));
JCTree.JCImport jcImport = treeMaker.Import(fieldAccess, false);
ListBuffer<JCTree> imports = new ListBuffer<>();
imports.append(jcImport);
for (int i = 0; i < compilationUnit.defs.size(); i ) {
imports.append(compilationUnit.defs.get(i));
}
compilationUnit.defs = imports.toList();
}
本文并非只是贴代码,所以后面两步不再贴出来,以上内容也不解释,因为我会在后面的文章中逐个讲解,上面代码只为给大家一个直观的开发过程。