原理就是读入java源代码, 解析注解, 然后生成新的java代码. 新生成的java代码最后被编译成java字节码, 注解助力器不能改变读入的java类, 比如不能加入或删除java方法.
一、AbstractProcessor
@AutoService(Processor.class)
public class MyProcessor extends AbstractProcessor {
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {...}
@Override
public Set getSupportedAnnotationTypes() {...}
@Override
public SourceVersion getSupportedSourceVersion() {...}
@Override
public boolean process(Set extends TypeElement> annotations, RoundEnvironment roundEnv) {...}
}
1.1 init(...)
所有的注解处理器类都必须有一个无参构造函数. init方法会被注解处理工具调用, 以ProcessingEnvironment作为参数. ProcessingEnvironment作为参数. ProcessingEnvironment提供了一些使用的工具类Elements, Types和Filer.
1.2 getSupportedAnnotationTypes(...)
在这个方法里面你必须指定哪些注解应该被注解处理器注册. 注意, 它的返回值是一个String集合, 包含了你的注解处理器想要处理的注解类型的全称. 换句话说, 你在这里定义你的注解处理器要处理哪些注解.
1.3 process(...)
类似于每个处理器的main()方法. 你可以在这个方法里面编码实现扫描, 处理注解, 生成java文件. 使用RoundEnvironment参数, 你可以查询被特定注解标注的元素.
1.3.1 RoundEnvironment
- 运行环境, 通过该变量可以获取被特定注解标注的元素的集合
public interface RoundEnvironment {
Set extends Element> getElementsAnnotatedWith(TypeElement a);
Set extends Element> getElementsAnnotatedWith(Class extends Annotation> a);
}
二、ProcessingEnvironment
public interface ProcessingEnvironment {
// 用于编译时期在控制台输出日志时使用
Messager getMessager();
// 输出文件时使用.
Filer getFiler();
// 元素相关的辅助类.
Elements getElementUtils();
Types getTypeUtils();
}
三、Elements作为工具类, 提供对应的Element
public interface Elements {
PackageElement getPackageElement(CharSequence name);
TypeElement getTypeElement(CharSequence name);
}
四、Element(注意与Elements的区别)
- 在注解处理器过程中, 我们扫描所有的java源文件, 源代码的每一个部分都是一个特定类型的Element, Element代表程序的元素, 例如包、类或者方法, 每个Element代表一个静态的、语言级别的构件.
package com.example; // PackageElement
public class Foo { // TypeElement
private int a; // VariableElement
private Foo other; // VariableElement
public Foo () {} // ExecuteableElement
public void setA ( // ExecuteableElement
int newA // TypeElement
) {}
}
4.1 Element的子类
类型 | 概念 |
---|---|
ExecutableElement | 表示某个类或接口的方法、构造方法 |
PackageElement | 表示一个包程序元素, 提供对有关包及其成员的信息的访问 |
TypeElement | 表示一个类或接口程序元素, 提供对有关类型及其成员的信息的访问 |
VariableElement | 表示一个字段、enum常量、方法或构造方法参数、局部变量或异常参数 |
4.2 ElementKind
- 如果要判断一个Element的类型, 最好使用Element.getKind()配合ElementKind一起使用. 例如Class和Interface对应的类型都为TypeElement, 无法进一步细分, 但是通过ElementKind.CLASS、ElementKind.INTERFACE可以将他俩进行细分.
public enum ElementKind {
// A package: 包类型
PACKAGE,
// An enum type: 枚举类型
ENUM,
// 类类型或者枚举类型
CLASS,
// An annotation type: 注解类型
ANNOTATION_TYPE,
// An interface not described by a more specific kind: 接口类型
INTERFACE,
// An enum constant: 枚举常量
ENUM_CONSTANT,
// A field not described by a more specific kind: 变量
FIELD,
// A parameter of a method or constructor: 普通/构造方法的方法参数
PARAMETER,
// A local variable: 局部变量
LOCAL_VARIABLE,
// A parameter of an exception handler:
EXCEPTION_PARAMETER,
// A method: 方法
METHOD,
// constructor: 构造函数
CONSTRUCTOR,
// A static initializer: 静态变量初始化
STATIC_INIT,
// An instance initializer: 实例初始化
INSTANCE_INIT,
// A type parameter: 参数类型
TYPE_PARAMETER,
// An implementation-reserved element. This is not the element you are looking for.
OTHER,
// A resource variable. @since 1.7
RESOURCE_VARIABLE;
}