编译时注解从入门到精通(四)

本篇文章是以类元素(element)为主体进行探讨的。为了简化代码,我把类元素的两个兄弟提前声明出来:

1
2
3
4
5
// 类的标识
Symbol.ClassSymbol classSym = (Symbol.ClassSymbol) element;

// 类的声明
JCTree.JCClassDecl classDecl = (JCTree.JCClassDecl) trees.getTree(element);

查询相关

获取类的全路径

1
2
3
4
5
6
7
8
/**
* 获取类的全路径
*
* @return 返回类的全路径
*/
public String getFullName() {
return classSym.fullname.toString();
}

获取类的包名

1
2
3
4
5
6
7
8
/**
* 获取类的包名
*
* @return 返回类的包名
*/
public String getPackageName() {
return classSym.owner.toString();
}

获取类名

1
2
3
4
5
6
7
8
/**
* 获取类名
*
* @return 返回类名
*/
public String getClassName() {
return classSym.name.toString();
}

判断是否有指定的修饰符

1
2
3
4
5
6
7
8
/**
* 判断类是不是有某个修饰符
*
* @return 如果类有某个修饰符的返回true,否则返回false
*/
public boolean hasModifier(int modifier) {
return classDecl.mods.flags % (modifier * 2) >= modifier;
}

判断有没有实现指定的接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* 判断有没有实现指定的接口
*
* @param interfaceClass 接口
* @return 如果类已经实现了指定接口则返回true,否则返回false
*/
private boolean hasInterface(Class<?> interfaceClass) {
for (JCTree.JCExpression impl : classDecl.implementing) {
if (impl.type.toString().equals(interfaceClass.getName())) {
return true;
}
}
return false;
}

判断是否存在字段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* 判断是否存在字段
*
* @param fieldName 字段名
* @return 若存在返回true,否则返回false
*/
private boolean existsField(String fieldName) {
for (JCTree jcTree : classDecl.defs) {
if (jcTree.getKind() == Tree.Kind.VARIABLE) {
JCTree.JCVariableDecl var = (JCTree.JCVariableDecl) jcTree;
if (fieldName.equals(var.name.toString())) {
return true;
}
}
}
return false;
}

修改相关

设置类的修饰符

1
2
3
4
5
6
7
8
/**
* 设置类的修饰符
*
* @param modifier 修饰符
*/
public void setModifier(int modifier) {
classDecl.mods.flags = modifier;
}

导入一个包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* 导入一个包
*
* @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();
}

添加接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* 添加接口
*
* @param interfaceClass 接口类
*/
public void addInterface(Class<?> interfaceClass) {
// 判断类有没有实现此接口
if (!hasInterface(interfaceClass)) {
// 导包(会自动去重)
importPackage(this, interfaceClass);

java.util.List<JCTree.JCExpression> implementing = classDecl.implementing;
ListBuffer<JCTree.JCExpression> statements = new ListBuffer<>();
for (JCTree.JCExpression impl : implementing) {
statements.append(impl);
}

Symbol.ClassSymbol sym = new Symbol.ClassSymbol(Sequence.nextLong(), names.fromString(interfaceClass.getSimpleName()), null);
statements.append(treeMaker.Ident(sym));
classDecl.implementing = statements.toList();
}
}

设置无参数私有构造器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* 设置无参数私有构造器
*/
public void setNoArgPrivateConstructor() {
// 遍历类的所有字段和方法
for (JCTree jcTree : classDecl.defs) {
// 只处理方法
if (jcTree instanceof JCTree.JCMethodDecl) {
JCTree.JCMethodDecl methodDecl = (JCTree.JCMethodDecl) jcTree;
// 如果是构造方法 并且 没有参数
if (JcaConstants.CONSTRUCTOR_NAME.equals(methodDecl.name.toString()) && methodDecl.params.isEmpty()) {
// 把修饰符改为private
methodDecl.mods = treeMaker.Modifiers(Flags.PRIVATE);
}
}
}
}

当然,肯定还会有其他需求,不过只要这些你掌握了,其他应该问题都不大。

更多用法请参考:https://github.com/ofofs/jca.git