Earth Guardian

You are not LATE!You are not EARLY!

0%

Java 注解解析 -- 处理器解析

Java 注解的解析有两种方式:反射和注解处理器(APT/JSR 269),本文主要介绍注解处理器解析方式。

  • 解析方式
    注解处理器解析注解的方式,是在编译期解析的,所以对注解的 Rentention 没有要求(即使 RetentionPolicy.SOURCE 也可以),可以根据编码需求自行设定。
  • 工具属性
    注解处理器是 javac 的一个工具,它用来在编译时扫描和处理对应注解。一个注解的注解处理器,通常以 Java 代码(或者编译过的字节码)作为输入,生成文件(通常是 .java 文件)作为输出。这些生成的 Java 代码是在新生成的 .java 文件中,所以不能修改已经存在的 Java 类,例如向已有的类中添加方法。这些生成的 .java 文件,会同其他普通的手动编写的 Java 源代码一样被 javac 编译。
  • 独立进程
    注解处理器是运行它自己的虚拟机 JVM 中的,javac 启动一个完整 Java 虚拟机来运行注解处理器,所以可以把注解处理器库看做一个独立的 Java 项目。

自定义注解处理器流程

自定义注解和自定义注解处理器建议分成两个 jar 包,自定义注解处理器仅仅在编译期需要用到,所以工程中不需要将处理器打包到目标代码中。

自定义注解库 Custom Annotation

AS 中新建 Java 库:File --> New --> New Module --> Java Libary ,新建 myanno 注解库。

Gradle 文件:

1
2
3
4
5
6
7
8
9
10
// Java 库
apply plugin: 'java-library'

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
}

// 使用 Java 1.8 来编译
sourceCompatibility = "1.8"
targetCompatibility = "1.8"

注解源文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 注解字段
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.FIELD)
public @interface Field {
String value();
}

// 注解类
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
public @interface Info {
String author();
String date();
int version() default 1;
String[] mails();
}

// 注解任意元素,Java 8 新增
@Target(ElementType.TYPE_USE)
@Retention(RetentionPolicy.RUNTIME)
public @interface AnyAnnotation {
String value();
}

Gradle 中选择该库,编译生成对应的 jar: myanno

自定义注解处理器 Custom Processor

同样,需要新建一个自定义处理器 Java 库:processors。自定义注解处理器有两个步骤:

  • 自定义注解处理器必须继承 AbstractProcessor
  • 库的资源文件夹中添加 javax.annotation.processing.Processor 文件

继承 AbstractProcessor

自定义注解处理器必须继承 AbstractProcessor ,使用 @SupportedAnnotationTypes 定义支持解析的注解,并重写 process 处理对应注解。

1
2
3
4
5
6
7
8
9
10
@SupportedAnnotationTypes({"com.ymzs.annotation.Field"})
public class AnnotationParsingProcessor extends AbstractProcessor{

@Override
public boolean process(Set<? extends TypeElement> set,
RoundEnvironment roundEnvironment) {
System.out.println("AnnotationParsingProcessor::process");
return false;
}
}

添加 javax.annotation.processing.Processor 文件

为了将自定义注解处理器注册到 javac 时,必须打包一个特殊的文件 javax.annotation.processing.ProcessorMETA-INF/services 目录下。原因见 Java 技术手册

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 源码目录结构
main
-java
-com
-ymzs
-parsing
-AnnotationParsingProcessor.java
-resources
-META-INF
-services
-javax.annotation.processing.Processor

// jar 包目录结构
processors.jar
-com
-ymzs
-parsing
-AnnotationParsingProcessor.class
-META-INF
-services
-javax.annotation.processing.Processor
-MANIFEST.MF

javax.annotation.processing.Processor 文件的内容是一个列表,每一行对应一个注解处理器的全称。例如:

1
2
com.ymzs.parsing.AnnotationParsingProcessor
com.ymzs.parsing.OtherProcessor

Gradle 中选择该库,编译生成对应的 jar: processors

注解处理器插件

AS 中使用自定义注解处理器需要添加对应的 gradle 插件:

1
2
3
4
5
6
7
8
9
10
11
12
13
plugins{
id 'java-library'
// 使用 net.ltgt.apt 插件,版本为最新的 0.15
id "net.ltgt.apt" version "0.15"
}

dependencies {
...
// 自定义注解库
implementation project(":myanno")
// 使用自定义注解库解析注解
annotationProcessor project(":processors")
}
  • Android 环境
    Google 在发布 AS 时,开发了对应的 android-gradle-plugin,这是一系列插件包,并包含注解处理器插件:Android 注解处理器插件使用方法
    使用该插件时,被注解代码工程的 gradle 文件中需要包含如下信息,关键词 annotationProcessor
1
2
3
4
5
6
7
8
9
10
11
// 使用 android-gradle-plugin 插件中的 application 
apply plugin: 'com.android.application'

dependencies {
...
// Custom Annotation and Processor
// 自定义注解库
implementation project(":myanno")
// 使用自定义处理器库解析注解
annotationProcessor project(":processors")
}

结果验证

Gradle Projects 窗口中,选择需要被注解代码工程,选择 Tasks --> build --> assemble 编译工程,能正确的打印自定义注解处理器中的 Log

1
2
3
4
// 代码工程编译期,解析注解
:javabase:compileJava
// 自定义注解处理器解析注解
AnnotationParsingProcessor::process

APTJSR269

  • APT
    APT: Annotation-Processing Tool,相关 API 都在 com.sun.mirror 包下。从 Java 7 开始就被降级了,在 Java 8 被彻底移除,APT 移除原因
  • JSR269
    JSR 269 API: Pluggable Annotation Processing API,相关 API 都在 javax.annotation.processing, javax.lang.model 包下。从 Java 6 开始引入,后续版本逐步代替了 APTJSR 269

不管是那种 API ,它们都是处理注解的工具,对源代码文件进行检测,并找出对应注解后解析(或生成对应文件)。通常用来简化开发者的工作量,或者生成附属文件。虽然 APT 被移除了,但是因为历史原因,注解处理器还是常用 APT 来称呼。本文都是基于 JSR 269 API 实现的自定义注解处理器。

AnnotatedConstruct 体系

类图结构

0082-AnnotatedConstruct-uml.png

AnnotatedConstruct 基本类

AnnotatedConstruct JavaDoc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public interface AnnotatedConstruct {
// 返回直接存在于此元素上的注解集合
List<? extends AnnotationMirror> getAnnotationMirrors();
// 返回指定类型的注解
<A extends Annotation> A getAnnotation(Class<A> var1);
// 返回指定类型注解集合
<A extends Annotation> A[] getAnnotationsByType(Class<A> var1);
}

// 表示一个注解
public interface AnnotationMirror {
// 返回注解的类型
DeclaredType getAnnotationType();
// 获取注解的:成员变量名(方法) 和对应的值,放到一个 Map 中
Map<? extends ExecutableElement, ? extends AnnotationValue>
getElementValues();
}

// 表示注解的值
public interface AnnotationValue {
// 获取注解值
Object getValue();
String toString();
<R, P> R accept(AnnotationValueVisitor<R, P> var1, P var2);
}

TypeMirror 体系

TypeMirror JavaDoc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
public enum TypeKind {
// 基本数据类型
BOOLEAN,
BYTE,
SHORT,
INT,
LONG,
CHAR,
FLOAT,
DOUBLE,
VOID,
NONE,
NULL,
ARRAY,
// 类或者接口
DECLARED,
// 类或接口不能被解析
ERROR,
// 类型变量
TYPEVAR,
WILDCARD,
PACKAGE,
// 普通方法,构造方法,或者初始化代码
EXECUTABLE,
OTHER,
UNION,
INTERSECTION;

private TypeKind() {
}

public boolean isPrimitive() {
switch(this) {
case BOOLEAN:
case BYTE:
case SHORT:
case INT:
case LONG:
case CHAR:
case FLOAT:
case DOUBLE:
return true;
default:
return false;
}
}
}

// 表示 Java 编译语言中的类型
public interface TypeMirror extends AnnotatedConstruct {
// 返回类型的具体类别
TypeKind getKind();
boolean equals(Object var1);
int hashCode();
String toString();
<R, P> R accept(TypeVisitor<R, P> var1, P var2);
}

// 相交类型,即使用 & 符号连接的,比如类型变量边界
// 1.8 新增
public interface IntersectionType extends TypeMirror {
// 获取边界列表
List<? extends TypeMirror> getBounds();
}

// 联合类型,表示多个异常联合在一起,使用 | 连接
// 1.7 新增
public interface UnionType extends TypeMirror {
// 返回异常列表
List<? extends TypeMirror> getAlternatives();
}

// 可执行类型:方法、构造方法、初始化代码等
public interface ExecutableType extends TypeMirror {
// 返回类型变量列表
List<? extends TypeVariable> getTypeVariables();
// 返回值类型
TypeMirror getReturnType();
// 参数列表
List<? extends TypeMirror> getParameterTypes();
// 接收者类型
TypeMirror getReceiverType();
// 抛出列表
List<? extends TypeMirror> getThrownTypes();
}

public interface NoType extends TypeMirror {}

public interface PrimitiveType extends TypeMirror {}

// 通配符类型
public interface WildcardType extends TypeMirror {
// 上界
TypeMirror getExtendsBound();
// 下界
TypeMirror getSuperBound();
}

// 引用类型
public interface ReferenceType extends TypeMirror {}


public interface ArrayType extends ReferenceType {
// 数组原始类型
TypeMirror getComponentType();
}

public interface NullType extends ReferenceType {}

// 类型变量
public interface TypeVariable extends ReferenceType {
// 类型变量对应的元素
Element asElement();
TypeMirror getUpperBound();
TypeMirror getLowerBound();
}

// 声明类型,类或者接口,包含泛型。
public interface DeclaredType extends ReferenceType {
// 对应的元素
Element asElement();
// 获取封装此类型的类型
TypeMirror getEnclosingType();
// 返回泛型的实际类型参数列表:比如 Outer<String>.Inner<Number>
List<? extends TypeMirror> getTypeArguments();
}

public interface ErrorType extends DeclaredType {}

Element 体系

Element JavaDoc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
// 表示元素类别
public enum ElementKind {
PACKAGE,
ENUM,
CLASS,
ANNOTATION_TYPE,
INTERFACE,
ENUM_CONSTANT,
FIELD,
PARAMETER,
LOCAL_VARIABLE,
EXCEPTION_PARAMETER,
METHOD,
CONSTRUCTOR,
STATIC_INIT,
INSTANCE_INIT,
TYPE_PARAMETER,
OTHER,
RESOURCE_VARIABLE;

private ElementKind() {
}

public boolean isClass() {
return this == CLASS || this == ENUM;
}

public boolean isInterface() {
return this == INTERFACE || this == ANNOTATION_TYPE;
}

public boolean isField() {
return this == FIELD || this == ENUM_CONSTANT;
}
}

// 表示元素的修饰符
public enum Modifier {
PUBLIC,
PROTECTED,
PRIVATE,
ABSTRACT,
DEFAULT,
STATIC,
FINAL,
TRANSIENT,
VOLATILE,
SYNCHRONIZED,
NATIVE,
STRICTFP;

private Modifier() {
}

public String toString() {
return this.name().toLowerCase(Locale.US);
}
}

// 表示内部类类型
public enum NestingKind {
TOP_LEVEL,
MEMBER,
LOCAL,
ANONYMOUS;

private NestingKind() {
}

public boolean isNested() {
return this != TOP_LEVEL;
}
}

// 表示程序任意元素,如:包、类、方法、字段属性、类型变量等
public interface Element extends AnnotatedConstruct {
// 返回这个元素的类型
TypeMirror asType();
// 返回这个元素的类别
ElementKind getKind();
// 返回修饰符
Set<Modifier> getModifiers();
// 返回简单名称
Name getSimpleName();
// 返回封装此元素的元素,比如类,包等
Element getEnclosingElement();
// 返回此元素封装元素内部的所有子元素,
// 如果封装元素是类,则返回类内部定义的所有变量,方法等
List<? extends Element> getEnclosedElements();
boolean equals(Object var1);
int hashCode();
// 返回直接存在于此元素上的注解集合
List<? extends AnnotationMirror> getAnnotationMirrors();
// 返回指定类型注解
<A extends Annotation> A getAnnotation(Class<A> var1);
// 返回指定的结果
<R, P> R accept(ElementVisitor<R, P> var1, P var2);
}

// 表示包含限定名的能力
public interface QualifiedNameable extends Element {
// 返回全名称
Name getQualifiedName();
}

// 表示包元素
public interface PackageElement extends Element, QualifiedNameable {
Name getQualifiedName();
Name getSimpleName();
List<? extends Element> getEnclosedElements();
// 判断是否为未命名的包
boolean isUnnamed();
Element getEnclosingElement();
}

// 表示变量元素:字段、常量、参数等
public interface VariableElement extends Element {
// 返回常量的值,其他变量返回 null
Object getConstantValue();
Name getSimpleName();
Element getEnclosingElement();
}

// 表示泛型,参数化类型元素
public interface TypeParameterElement extends Element {
// 返回定义此类型变量的类、接口、方法、构造方法等
Element getGenericElement();
// 返回类型变量边界的类型集合
List<? extends TypeMirror> getBounds();
Element getEnclosingElement();
}

// 表示拥有泛型的能力
public interface Parameterizable extends Element {
// 返回泛型集合
List<? extends TypeParameterElement> getTypeParameters();
}

// 表示类或接口的方法、构造方法或初始化程序(静态或实例),包括注解类型元素
public interface ExecutableElement extends Element, Parameterizable {
List<? extends TypeParameterElement> getTypeParameters();
// 返回值类型
TypeMirror getReturnType();
// 参数列表
List<? extends VariableElement> getParameters();
// 返回接受者类型
TypeMirror getReceiverType();
// 判断是否为可变长参数
boolean isVarArgs();
// 判断是否为接口的 default 方法
boolean isDefault();
// 返回抛出类型集合
List<? extends TypeMirror> getThrownTypes();
// 如果是注解元素,返回其默认值
AnnotationValue getDefaultValue();
Name getSimpleName();
}

// 表示类或接口元素
public interface TypeElement extends Element, Parameterizable,
QualifiedNameable {
List<? extends Element> getEnclosedElements();
// 返回类的类型,即内部类类型
NestingKind getNestingKind();
Name getQualifiedName();
Name getSimpleName();
// 返回父类的类型
TypeMirror getSuperclass();
// 返回接口的类型集合
List<? extends TypeMirror> getInterfaces();
List<? extends TypeParameterElement> getTypeParameters();
Element getEnclosingElement();
}

源代码的每一个部分都是一个特定类型的 Element,也就是说 Element 代表程序的任意元素,例如包、类、方法等。每个 Element 代表一个静态的、语言级别的构件。

1
2
3
4
5
6
7
8
9
10
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
) {}
}

换个角度来看源代码,它只是结构化的文本,不是可运行的。可以想象它就像要被解析的 XML 文件一样(或者是编译器中抽象的语法树)。就像 XML 解释器一样,有一些类似 DOM 的元素,可以从一个元素导航到它的父或者子元素上。
举例来说,假如有一个代表 public class Foo 类的 TypeElement 元素,可以遍历它的所有元素:

1
2
3
4
TypeElement fooClass = ... ;  
for (Element e : fooClass.getEnclosedElements()){ // iterate over children
Element parent = e.getEnclosingElement(); // parent == fooClass
}

Elements 接口

用来处理 Element 的工具类,Elements JavaDoc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public interface Elements {
// 返回全限定名的包元素
PackageElement getPackageElement(CharSequence name);
// 返回类或接口元素
TypeElement getTypeElement(CharSequence name);
// 获取注解的:成员变量名(方法) 和对应的值,放到一个 Map 中
Map<? extends ExecutableElement, ? extends AnnotationValue>
getElementValuesWithDefaults(AnnotationMirror var1);
// 返回元素的 Javadoc 文档
String getDocComment(Element var1);
boolean isDeprecated(Element var1);
// 返回元素的二进制名称
Name getBinaryName(TypeElement var1);
// 返回元素的包元素
PackageElement getPackageOf(Element var1);
// 返回元素的所有成员
List<? extends Element> getAllMembers(TypeElement var1);
// 返回元素的所有注解列表
List<? extends AnnotationMirror> getAllAnnotationMirrors(Element var1);
// 判断元素是否隐藏了另外一个元素
boolean hides(Element hider, Element hidden);
// 判断给定元素的方法,是否被重写
boolean overrides(ExecutableElement overrider,
ExecutableElement overridden, TypeElement type);
// 常量值转换为字符串
String getConstantExpression(Object var1);
void printElements(Writer var1, Element... var2);
Name getName(CharSequence var1);
boolean isFunctionalInterface(TypeElement var1);
}

Types 接口

用来处理 TypeMirror 的工具类,Types JavaDoc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public interface Types {
// 返回类型对应的元素
Element asElement(TypeMirror var1);
boolean isSameType(TypeMirror var1, TypeMirror var2);
boolean isSubtype(TypeMirror var1, TypeMirror var2);
// 判断类型是否可以指派给另外一种类型
boolean isAssignable(TypeMirror var1, TypeMirror var2);
boolean contains(TypeMirror var1, TypeMirror var2);
// 测试方法的签名是否为另一个方法的子签名
boolean isSubsignature(ExecutableType var1, ExecutableType var2);
// 返回直接超类型列表,接口排在最后
List<? extends TypeMirror> directSupertypes(TypeMirror var1);
// 类型擦除后的类型
TypeMirror erasure(TypeMirror var1);
// 基本类型的封装类型,类型装箱
TypeElement boxedClass(PrimitiveType var1);
// 类型拆箱
PrimitiveType unboxedType(TypeMirror var1);
// 参数化类型转换
TypeMirror capture(TypeMirror var1);
PrimitiveType getPrimitiveType(TypeKind var1);
NullType getNullType();
NoType getNoType(TypeKind var1);
ArrayType getArrayType(TypeMirror var1);
// 根据指定上界或下界,返回通配符类型
WildcardType getWildcardType(TypeMirror extendsBound,
TypeMirror superBound);
// 返回元素和指定类型的泛型
DeclaredType getDeclaredType(TypeElement typeElem,
TypeMirror... typeArgs);
// 根据给定的包含类型,返回元素和指定类型的泛型
DeclaredType getDeclaredType(DeclaredType containing,
TypeElement typeElem, TypeMirror... typeArgs);
// 如果指定元素是指定类型的成员,则返回其类型
TypeMirror asMemberOf(DeclaredType containing, Element element);
}

Filer 接口

用来创建文件,Filer JavaDoc

1
2
3
4
5
6
7
8
9
10
public interface Filer {
JavaFileObject createSourceFile(CharSequence var1, Element... var2)
throws IOException;
JavaFileObject createClassFile(CharSequence var1, Element... var2)
throws IOException;
FileObject createResource(Location var1, CharSequence var2,
CharSequence var3, Element... var4) throws IOException;
FileObject getResource(Location var1, CharSequence var2,
CharSequence var3) throws IOException;
}

Messager 接口

提供给注解处理器一个报告错误、警告以及提示信息的途径。Messager JavaDoc , 消息级别 Diagnostic.Kind
因为注解处理器是在独立的 java 虚拟机运行,所以注解处理器中不能直接进行异常抛出,否则进程异常崩溃时,会弹出一大堆让人捉摸不清的堆栈调用日志显示,也就是目标工程报的错误来自于另外一个虚拟机的堆栈。通常使用 Messager 来写一些信息给使用此注解器的第三方开发者的。在官方文档中描述了消息的不同级别,非常重要的是 Kind.ERROR,因为这种类型的信息用来表示我们的注解处理器处理失败了,很有可能是第三方开发者错误的使用了注解。

1
2
3
4
5
6
7
8
9
// 打印信息
public interface Messager {
void printMessage(Kind var1, CharSequence var2);
void printMessage(Kind var1, CharSequence var2, Element var3);
void printMessage(Kind var1, CharSequence var2, Element var3,
AnnotationMirror var4);
void printMessage(Kind var1, CharSequence var2, Element var3,
AnnotationMirror var4, AnnotationValue var5);
}

AbstractProcessor 详细分析

自定义处理器通常会继承 AbstractProcessor,并重写对应方法,来实现自定义注解的解析。所有的注解处理器类都必须有一个无参构造函数,否则执行时会报错。
对应源码文件目录:src\javax\annotation\processing

类图结构

0082-Processor-uml.png

常用 API 介绍

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public interface Processor {

Set<String> getSupportedOptions();

// 必须指定:表示当前注解处理器支持哪些注解
// 返回值是一个字符串的集合,字符串为注解类型的合法全称
// 比如:Field.class.getCanonicalName(),或者 com.xxx.Field
Set<String> getSupportedAnnotationTypes();

// 指定使用的 Java 版本,默认返回 SourceVersion.RELEASE_6
// 通常使用最新版本作为返回值:SourceVersion.latestSupported()
SourceVersion getSupportedSourceVersion();

// 注解处理器运行的第一个方法,初始化环境
void init(ProcessingEnvironment processingEnv);

// 注解处理器解析注解的入口
boolean process(Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv);

//
Iterable<? extends Completion> getCompletions(Element element,
AnnotationMirror annotation, ExecutableElement member,
String userText);
}

// AbstractProcessor 实现了 Processor 大部分接口
// 只有 process 是抽象的,需要子类去实现
public abstract class AbstractProcessor implements Processor {
...
public abstract boolean process(Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv);
...
}

两个有用的注解

  • @SupportedAnnotationTypes
    表示当前类支持的注解的完整类路径,支持通配符。当前 Processor 要处理的 Annotation 名字全称。等同于 getSupportedAnnotationTypes() ,支持通配符,使用 * 表示支持所有注解。
  • @SupportedSourceVersion
    表示该处理器支持的源码版本。等同于 getSupportedSourceVersion()

循环调用 process

process 通常会被执行两次:根据 Log 可以发现,process 的返回值不管是 true/false 都会被执行两次?但是解析注解时,只有第一次执行 process 时,roundEnvironment.getElementsAnnotatedWith 才能获取到注解。
具体原因参考 Processor JavaDoc 。官方文档中第一段就介绍了,注解处理器是个循环处理的过程,每次循环都会解析上次处理器产生的源文件。也就是说第一次 process 处理了编写的源文件,第二次处理了注解处理器生成的源文件(此时已经不包含被处理的注解了),直到所有支持的注解都被解析完毕。

存在的问题

不管是使用 @SupportedAnnotationTypes 还是重写 getSupportedAnnotationTypes() ,只要支持注解包其中一个注解,注解处理器就能解析该包中的所有其他注解。

1
2
3
4
// Java library: myanno
@Info
@Field
@AnyAnnotation

注解包 myanno 包含三个注解,但是在自定义注解器中,代码中规定只支持 Field 注解,自定义注解器仍然能解析 Info, AnyAnnotation

注解处理器插件

  • gradle-apt-plugin
    Java 环境下注解插件,使用方法:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    plugins{
    id "net.ltgt.apt" version "0.15"
    }
    dependencies {
    // 本地注解库
    annotationProcessor project(":processors")
    // 引用网络开源注解库
    annotationProcessor "com.custom:CustomProcessors:version1.2.3"
    }
  • android-apt
    Android 注解器框架,现在已经不再维护。
  • annotationProcessor
    Android Plugin for Gradlegooglegradle 开发的注解处理器框架,用于替换 android-apt。使用方法:
    1
    2
    3
    4
    // 本地注解库
    annotationProcessor ":customProcessors"
    // 引用网络开源注解库
    annotationProcessor "com.custom:CustomProcessors:version1.2.3"

常用开源库

  • AutoService 官网
    自动生成 javax.annotation.processing.Processor 文件,并将自定义注解处理器按照规范加入该文件。
  • JavaPoet 官网
    生成 .java 源文件的 API 接口,非常强大实用。解析自定义注解时,可以使用 JavaPoet 来生成对应文件。

AutoService 用法

  • build.gradle 文件中添加依赖
    implementation 'com.google.auto.service:auto-service:1.0-rc4' 具体版本号,到 github 官网上查看。
  • 自定义注解处理器类上添加 AutoService 注解
    在自定义处理器类上,添加 @AutoService(Processor.class) 注解。该注解会自动生成对应的 META-INF/services/javax.annotation.processing.Processor 文件,并将自定义注解处理器按照规范加入该文件。

JavaPoet 用法

其他

调试注解处理器

常用场景

大量开源库都使用了注解处理器简化代码:

参考文档