- 注解生成器(一)拼接方式 可以知道通过拼接的方式生成注解代码还是比较繁琐
下面介绍一种模版形式:
基于第一篇的工程基础上,需要加上 javapoet依赖
apply plugin: 'java-library'
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
// AS3.4.1 + Gradle5.1.1 + auto-service:1.0-rc4
compileOnly'com.google.auto.service:auto-service:1.0-rc4'
annotationProcessor'com.google.auto.service:auto-service:1.0-rc4'
// 帮助我们通过类调用的形式来生成Java代码
implementation "com.squareup:javapoet:1.9.0"
// 依赖注解
implementation project(':annotation')
}
// java控制台输出中文乱码
tasks.withType(JavaCompile) {
options.encoding = "UTF-8"
}
sourceCompatibility = "7"
targetCompatibility = "7"
根据 Javapoet官方文档注解生成器模版:javapoet 源码介绍
- demo 演示代码
//需要生成的类
package com.example.helloworld;
public final class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, JavaPoet!");
}
}
//生成规则
MethodSpec main = MethodSpec.methodBuilder("main")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.returns(void.class)
.addParameter(String[].class, "args")
.addStatement("$T.out.println($S)", System.class, "Hello, JavaPoet!")
.build();
TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
.addMethod(main)
.build();
JavaFile javaFile = JavaFile.builder("com.example.helloworld", helloWorld)
.build();
javaFile.writeTo(System.out);
- 根据上面的演示demo模版实现注解生成器(一)拼接方式 中的功能
基于注解生成器(一)拼接方式 其他代码不用变,只需要修改 process回调中的代码
/**
* 相当于main函数,开始处理注解
* 注解处理器的核心方法,处理具体的注解,生成Java文件
*
* @param set 使用了支持处理注解的节点集合
* @param roundEnvironment 当前或是之前的运行环境,可以通过该对象查找找到的注解。
* @return true 表示后续处理器不会再处理(已经处理完成)
*/
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
if (set.isEmpty()) return false;
// 获取所有带ARouter注解的 类节点
Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(ARouter.class);
// 遍历所有类节点
for (Element element : elements) {
// 通过类节点获取包节点(全路径:com.netease.xxx)
String packageName = elementUtils.getPackageOf(element).getQualifiedName().toString();
// 获取简单类名
String className = element.getSimpleName().toString();
messager.printMessage(Diagnostic.Kind.NOTE, "被注解的类有:" + className);
// 最终想生成的类文件名
String finalClassName = className + "$$ARouter";
// 高级写法,javapoet构建工具,参考(https://github.com/JakeWharton/butterknife)
try {
// 获取类之上@ARouter注解的path值
ARouter aRouter = element.getAnnotation(ARouter.class);
// 构建方法体
MethodSpec method = MethodSpec.methodBuilder("findTargetClass") // 方法名
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.returns(Class.class) // 返回值Class<?>
.addParameter(String.class, "path") // 参数(String path)
// 方法内容拼接:
// return path.equals("/app/MainActivity") ? MainActivity.class : null
.addStatement("return path.equals($S) ? $T.class : null",
aRouter.path(), ClassName.get((TypeElement) element))
.build(); // 构建
// 构建类
TypeSpec type = TypeSpec.classBuilder(finalClassName)
.addModifiers(Modifier.PUBLIC) //, Modifier.FINAL)
.addMethod(method) // 添加方法体
.build(); // 构建
// 在指定的包名下,生成Java类文件
JavaFile javaFile = JavaFile.builder(packageName, type)
.build();
javaFile.writeTo(filer);
} catch (IOException e) {
e.printStackTrace();
}
}
return true;
}
上面的逻辑还是通过注解类,拿到对应的包名和类名然后去用Javapoet模版由下树节点往上自动生成动态类
最终生成的效果:依旧是可以生成,并且代码更具逻辑性。
image.png














网友评论