学习Activiti 6.0.0 (二)

思路

上一篇文章的最后有一个@Serial的注解,现在我捋一捋此注解实现的思路。

  1. 一个项目中有很多很多的类,我们要找出带有@Serial注解的类。然后遍历这些类,对其逐个处理。
  2. 我们给这个类实现Serializable接口(如果没实现),同时也要把对应的包导入进来。
  3. 生成一个不重复的long型的值,并赋值给一个叫做serialVersionUID的long型遍历。
  4. 最后把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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
for (Element element : elements) {
// 先获取到类的声明
JCTree.JCClassDecl classDecl = (JCTree.JCClassDecl) trees.getTree(element);

// 遍历类的所有接口, 如果没有实现Serializable接口,那么就需要实现
boolean hasSerializable = false;
List<JCTree.JCExpression> implementing = classDecl.implementing;
ListBuffer<JCTree.JCExpression> statements = new ListBuffer<>();
for (JCTree.JCExpression impl : implementing) {
statements.append(impl);
if (impl.type.toString().equals(Serializable.class.getName())) {
hasSerializable = true;
}
}

if (!hasSerializable) {
Symbol.ClassSymbol sym = new Symbol.ClassSymbol(Sequence.nextLong(), names.fromString(Serializable.class.getSimpleName()), null);
statements.append(treeMaker.Ident(sym));

// 把Serializable的包导入进来
importPackage(element, Serializable.class);
}
classDecl.implementing = statements.toList();
}

代码中出现的treestreeMakernames,是在JcaProcessorinit方法中获取的:

1
2
3
4
5
6
7
8
9
10
11
12
private 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();
}

本文并非只是贴代码,所以后面两步不再贴出来,以上内容也不解释,因为我会在后面的文章中逐个讲解,上面代码只为给大家一个直观的开发过程。