Annotation Processor(注解处理器)详解
2019-12-31 本文已影响0人
caoww
- 前言
- 注解处理器
- 自定义处理器
前言
- Java中的注解(Annotation)如果要被识别,离不开注解处理器。所以有必要来了解一下。
注解处理器
注解处理器(Annotation Processor)是javac的一个工具,不管是运行时注解还是编译时注解,都会通过处理器在编译时进行扫描和处理注解。
Java中有默认的注解处理器,使用者也可以自定义注解处理器,注册后使用注解处理器处理注解,最终达到注解本身起到的效果。
注解处理器将标记了注解的类,变量等作为输入内容,经过注解处理器处理,生成想要生成的java代码。所以处理器可以理解为就是一个生成代码的工具,只是是通过注解的规则生成。生成后的代码,可以看作是同一般代码,最终被编译。
自定义处理器
创建工程
- 自定义处理器需要创建java 库java- Library(自行创建)
添加依赖
- implementation 'com.google.auto.service:auto-service:1.0-rc3'
- implementation 'com.google.auto:auto-common:0.8'
创建自定义Processor类 如创建MyProcessor
- MyProcessor继承 AbstractProcessor 添加@AutoService(Processor.class)注解
如:
@AutoService(Processor.class)
public class PermissionProcessor extends AbstractProcessor {
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
}
@Override
public Set<String> getSupportedAnnotationTypes() {
return super.getSupportedAnnotationTypes();
}
@Override
public SourceVersion getSupportedSourceVersion() {
return super.getSupportedSourceVersion();
}
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
return false;
}
- init(ProcessingEnvironment processingEnvironment)
init()方法,它会被注解处理工具调用,并输入ProcessingEnviroment参数。
ProcessingEnviroment提供很多有用的工具类Elements, Types和Filer。
- getSupportedAnnotationTypes()
这里你必须指定,这个注解处理器是注册给哪个注解的。
注意,它的返回值是一个字符串的集合,包含本处理器想要处理的注解类型的合法全称。换句话说,你在这里定义你的注解处理器注册到哪些注解上。
- getSupportedSourceVersion()
用来指定你使用的Java版本。通常这里返回SourceVersion.latestSupported()。
如果你有足够的理由只支持Java 6的话,你也可以返回SourceVersion.RELEASE_6
建议使用前者
- process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment)
这相当于每个处理器的主函数main()。扫描、评估和处理注解的代码,以及生成Java文件。
输入参数RoundEnviroment,可以让你查询出包含特定注解的被注解元素。后面我们将看到详细的内容。
- 注:在Java 7中,你也可以使用注解来代替getSupportedAnnotationTypes()和getSupportedSourceVersion(),像这样:
@SupportedAnnotationTypes(“com.starcor.annotation.RouterAnnotation”),其中括号内内容表示要处理的注解名称,要写全名。
创建javax.annotation.processing.Processor 注册注解处理器
在使用注解处理器需要先声明,步骤:
1、需要在 processors 库的 main 目录下新建 resources 资源文件夹;
2、在 resources文件夹下建立 META-INF/services 目录文件夹
3、创建javax.annotation.processing.Processor文件
4、文件内容添加:com.xx.java.processor.MyProcessor 自己创建注解处理器的路径
ProcessingEnvironment 包含了注解处理器相关的工具类和编译器配置的参数
public interface ProcessingEnvironment {
Map<String, String> getOptions(); // 编译期间,app给注解处理器传的值
Messager getMessager(); // 在注解处理器处理注解生成新的源代码过程中,我们可用Messager来将一些错误信息打印到控制台上
Filer getFiler(); // 我们可以通过这个类来创建新的文件。
/**
* 它其实是一个工具类,用来处理所有的Element 元素,
* 而我们可以把生成代码的类中所有的元素都可以成为Element 元素,
* 如包就是PackageElement,
* 类/接口为TypeElement,
* 变量为VariableElement,
* 方法为ExecutableElement
*/
Elements getElementUtils();
/**
* 它其实也是一个工具类,只是用来处理TypeMirror. 也就是一个类的父类。
* TypeMirror superClassType = currentClass.getSuperclass();
*/
Types getTypeUtils();
SourceVersion getSourceVersion();
Locale getLocale();
}
RoundEnvironment 指在每一轮的扫描和处理源代码中获取被注解的Element
- 获取被注解的Element
Set<? extends Element> elementsAnnotatedWith = roundEnvironment.getElementsAnnotatedWith(GetPermissions.class);
- 遍历Element 获取相应添加注解的信息
mElementUtils.getPackageOf(element); // 获取包名, 通过工具类
TypeElement classElement = (TypeElement) element.getEnclosingElement(); // 获取类
classElement.getSimpleName().toString(); // 获取类名
element.getAnnotation(注解类.class); // 获取注解的实体类对象,可获取里面相应的值
element.getModifiers() // 获取修饰符
// 强转方法的Element
ExecutableElement methodElement = (ExecutableElement) element;
// 获取方法名
String methodName = methodElement.getSimpleName().toString();
executableElement.getParameters(); // 获取注解形参
executableElement.getReturnType(); // 获取返回值类型
enclosingElement.getTypeParameters(); // 获取返回值
executableElement.getThrownTypes(); // 获取方法throw的异常