Java 注解解析 -- 反射

Java 注解的解析有两种方式:反射和注释处理器(APT/JSR 269)。

本文主要介绍通过反射来解析注解,它是在运行时解析的,所以反射要求注解必须是 @Retention(RetentionPolicy.RUNTIME) 类型的。在 .class 文件和 JVM 中都会保留注解信息,运行时才能通过反射来获取并解析注解。但是反射比较慢,所以需要考虑效率问题。

注解体系

所有的注解都是 Annotation 的子接口,类中所有的元素都是 AnnotatedElement 的实现。

源码分析

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
// 所有注解的父接口
public interface Annotation {
boolean equals(Object obj);
int hashCode();
String toString();

// 返回注解自身的类型,如:interface com.***.CustomAnnotation
Class<? extends Annotation> annotationType();
}

// 被注解元素
public interface AnnotatedElement {
// 判断指定类型注解是否存在
default boolean isAnnotationPresent(Class<? extends Annotation>
annotationClass) {...}
// 返回指定类型注解,包含父类
<T extends Annotation> T getAnnotation(Class<T> annotationClass);
// 返回所有注解
Annotation[] getAnnotations();
// 返回指定类型的注解数组,包含父类中的
default <T extends Annotation> T[] getAnnotationsByType
(Class<T> annotationClass) {...}
// 返回当前元素上指定类型的注解
default <T extends Annotation> T getDeclaredAnnotation
(Class<T> annotationClass) {...}
// 返回当前元素上指定类型的注解数组
default <T extends Annotation> T[] getDeclaredAnnotationsByType
(Class<T> annotationClass) {...}
// 返回当前元素上注解的数组
Annotation[] getDeclaredAnnotations();
}

类图结构

0081-AnnotatedElement-uml.png

注解的本质

注解的位置只能放到类型前面,不能放到变量名,方法名之前。

注解是接口

注解使用关键字 @interface 来表示,实际上它也的确是接口。

1
2
3
4
5
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface BindView {
int value();
}

BindView 用来注解字段,并且在运行时也保留了注解信息。反编译结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
xmt@server005:~/annotation$ javap -v -c BindView.class
...
// 反编译发现注解实际就是一个接口文件,并继承了 Annotation
public interface BindView extends java.lang.annotation.Annotation
SourceFile: "BindView.java"
RuntimeVisibleAnnotations:
0: #9(#4=e#10.#11)
1: #12(#4=[e#13.#14])
minor version: 0
major version: 51
flags: ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
Constant pool:
...
{
public abstract int value();
flags: ACC_PUBLIC, ACC_ABSTRACT
}

反编译后发现所有的注解实际是接口,并且继承了 Annotation。所以使用反射解析注解时,可以使用父接口 Annotation 来表示任意注解类型

注解在 class 文件中

自定义注解如果标注为 CLASS, RUNTIME,表示会在 class 文件中保留注解信息。

1
2
3
4
public class TestAnnotation{
@BindView(2)
public int i;
}

测试类中使用 @BindView 注解整型变量 i,反编译结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
xmt@server005:~/annotation$ javap -v -c TestAnnotation
...
public class TestAnnotation
SourceFile: "TestAnnotation.java"
minor version: 0
major version: 51
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
...
#7 = Utf8 LBindView;
#8 = Utf8 value
#9 = Integer 2
...
{
public int i;
flags: ACC_PUBLIC
RuntimeVisibleAnnotations:
0: #7(#8=I#9)
...
}

反编译后发现,变量 i 中保留了一个 RuntimeVisibleAnnotations 标记。后续反射解析时,就是通过这个标记来获取相关注解的。

AnnotatedType 体系介绍

AnnotatedType 体系是 Java 8 新加的,是泛型 Type 体系对应的被注解类型。
AnnotatedType 既能获取被注解元素的类型,也能获取该元素上的注解数组。示例:@CustomAnnotation("value") CustomClass

  • AnnotatedType.getType
    被注解元素的类型,即 CustomClass
  • AnnotatedElement.getAnnotations
    该元素上的注解数组,即 {CustomAnnotation}

AnnotatedType 类型并不是一定会有注解,只是代表拥有被注解的能力。比如 int iAnnotatedType 仅仅代表整型 int,而它并没有被注解。

源码分析

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
// 被注解类型  
public interface AnnotatedType extends AnnotatedElement {
// 返回被注解元素的具体类型,如 CustomClass
public Type getType();
}

// 被注解的类型变量
public interface AnnotatedTypeVariable extends AnnotatedType {
// 返回被注解类型变量边界数组
AnnotatedType[] getAnnotatedBounds();
}

// 代表被注解的成员是数组,必须递归解析,每次只能拿到第一维数组的注解
public interface AnnotatedArrayType extends AnnotatedType {
// 返回被注解元素的数组元素类型
// 返回值可能还是 AnnotatedArrayType , 所以需要递归解析
// 比如 boolean[][][] 三维数组,返回值为 boolean[][]
AnnotatedType getAnnotatedGenericComponentType();
}

// 被注解泛型通配符类型
public interface AnnotatedWildcardType extends AnnotatedType {
// 被注解泛型通配符下界
AnnotatedType[] getAnnotatedLowerBounds();
// 被注解泛型通配符上界
AnnotatedType[] getAnnotatedUpperBounds();
}

// 被注解参数化类型
public interface AnnotatedParameterizedType extends AnnotatedType {
// 被注解参数化类型数组,即泛型参数列表数组
AnnotatedType[] getAnnotatedActualTypeArguments();
}

示例

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
// 声明了两个类型变量 S, T,其中 S 的边界是多限定
// 继承父类 Thread
// 实现了接口 Runnable, Cloneable, Serializable
public class TestGenericAnnotation<
@AnyAnnotation("classTypeParameter") S extends Number
& @AnyAnnotation("classTypeParameterBounds") Comparable,
T extends Cloneable, U>
extends @AnyAnnotation("extends") Thread
implements @AnyAnnotation("implements1") Runnable,
Cloneable, @AnyAnnotation("implements2") Serializable {

// 字段属性注释的标准写法
@AnyAnnotation("field")
public boolean typeAnnotatedBoolean;

public
@AnyAnnotation("array4") boolean
@AnyAnnotation("array1") []
@AnyAnnotation("array2") []
@AnyAnnotation("array3") []
typeAnnotatedArray;

public @AnyAnnotation("typeVariable") S s;
public @AnyAnnotation("beforeType") int array[];

// 泛型字段
public @AnyAnnotation("map1") Map<
@AnyAnnotation("map2") ? extends @AnyAnnotation("map3") String,
@AnyAnnotation("map4") List<@AnyAnnotation("map5") Object>>
typeAnnotatedMap;

// 方法注释的标准写法
@AnyAnnotation("return")
public <@AnyAnnotation("methodTypeParameter") U, V> Class<?>
typeAnnotatedMethod(
@AnyAnnotation("formalParameter") TestGenericAnnotation arg)
throws @AnyAnnotation("throwException") ClassNotFoundException {

// 方法中的局部变量注解无法通过反射来解析,只能在编译前解析
@AnyAnnotation("local_variable_type") int foo = 0;
throw new ClassNotFoundException();
}
}

反射解析注解

动态代理

反射解析注解都使用的是动态代理技术访问注解的键值对,解析类源码文件:AnnotationParser.java, AnnotationInvocationHandler.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class AnnotationParser {

// 解析注解,并将注解作为键值对返回
public static Map<Class<? extends Annotation>, Annotation>
parseAnnotations(byte[] rawAnnotations, ConstantPool constPool
, Class<?> container) {...}

// 最终都是通过 annotationForMap 来生成注解
// 使用了动态代理来访问原始注解
public static Annotation annotationForMap(
final Class<? extends Annotation> type,
final Map<String, Object> memberValues){

return AccessController.doPrivileged(new PrivilegedAction<Annotation>(){
public Annotation run() {
return (Annotation) Proxy.newProxyInstance(
type.getClassLoader(), new Class<?>[] { type },
new AnnotationInvocationHandler(type, memberValues));
}});
}
...
}

测试代码打印反射获取的 Annotation 类类型:

1
2
3
4
5
6
7
8
9
// 测试代码
Annotation[] annotations = TestAnnotation.class.getDeclaredAnnotations();
for (Annotation annotation : annotations){
System.out.println(annotation.getClass());
}

// 测试结果输出
class com.sun.proxy.$Proxy1
class com.sun.proxy.$Proxy3

从输出结果可以看出,反射获取的 Annotation 类类型都是动态代理生成新类的类名。

常规解析

被注解的的类:

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
@MetaAnnotation(
author = "xmt",
date = "2018.4.27",
currentVersion = 2,
reviewer = {"a", "b", "c"}
)
@Roles(value = {@Role(name = "doctor"), @Role(name = "police")})
public class TestAnnotation {

@BindView(2)
public String view;
private int count;

@Creatable
public TestAnnotation(){

}

public TestAnnotation(int i){
count = i;
}

/**
* This is testable method.
*/
@Testable
public void testJavaDoc(){
System.out.println("Annotation viewValue = " + view);
}

private void testAnnotationMethod(){

}
}

注解反射解析:

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
public class TestAnnotationParsingReflect {
private Class<?> clazz = TestAnnotation.class;
private Object testAnnotation = null;
// 反射解析类
private void parsingClass(){
// 获取当前类上的注解
Annotation[] annotations = clazz.getDeclaredAnnotations();
for (Annotation annotation : annotations){
// 解析自定义的 MetaAnnotation 注解
if (annotation instanceof MetaAnnotation){
MetaAnnotation metaAnnotation = (MetaAnnotation) annotation;
System.out.println("author: " + metaAnnotation.author());
System.out.println("date: " + metaAnnotation.date());
System.out.println("currentVersion: "
+ metaAnnotation.currentVersion());
StringBuilder builder = new StringBuilder();
for (String s : metaAnnotation.reviewer()){
builder.append(s);
builder.append(" ");
}
System.out.println("reviewer: " + builder.toString());
// 解析自定义 Roles 注解
}else if (annotation instanceof Roles){
Roles roles = (Roles) annotation;
// 重复注解的解析
for ( Role role : roles.value()){
System.out.println("name: " + role.name());
}
}
}
}

// 解析构造方法上的注解
private void parsingConstructor(){
// 获取当前类中的构造方法
Constructor[] constructors = clazz.getDeclaredConstructors();
for (Constructor constructor : constructors){
// 获取每个构造方法上的注解
Annotation[] annotations = constructor.getDeclaredAnnotations();
for (Annotation annotation : annotations){
// 解析自定义 Creatable 注解
if (annotation instanceof Creatable){
try {
// 如果被 Creatable 注解过的构造方法
// 自动实例化一个对象
testAnnotation = constructor.newInstance(null);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
}

// 解析属性上的注解
private void parsingField(){
// 获取当前类中的属性字段
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields){
// 获取每个字段上的注解
Annotation[] annotations = field.getDeclaredAnnotations();
for (Annotation annotation : annotations){
// 解析自定义 BindView 注解
if (annotation instanceof BindView){
if (testAnnotation != null){
int value = ((BindView) annotation).value();
try {
// 如果被 BindView 注解的字段
// 将注解的成员变量值赋值给该字段
field.set(testAnnotation, String.valueOf(value));
System.out.println("set testAnnotation."
+ field.getName() + " = " + value);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
}

// 解析普通方法上的注解
private void parsingMethod(){
// 获取当前类中的普通方法
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods){
// 获取该方法上的注解
Annotation[] annotations = method.getDeclaredAnnotations();
for (Annotation annotation : annotations){
// 解析自定义 Testable 注解
if (annotation instanceof Testable){
if (testAnnotation != null){
try {
// 如果被 Testable 注解
// 自动调用该方法
method.invoke(testAnnotation, null);
System.out.println("invoke testAnnotation."
+ method.getName());
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
}
}

public static void main(String[] args) {
TestAnnotationParsingReflect reflect =
new TestAnnotationParsingReflect();
reflect.parsingClass();
reflect.parsingConstructor();
reflect.parsingField();
reflect.parsingMethod();
}
}

AnnotatedType 体系解析

AnnotatedTypeJava 8 新增加强型注解,可以注解到任意代码位置,如下示例为解析 TestGenericAnnotation 类中的所有注解。

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
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
public class TestGenericAnnotationParsingReflect {
// 被解析的类为 TestGenericAnnotation
private Class<?> clazz = TestGenericAnnotation.class;

// 解析类上的注解
private void parsingClass(){
// 解析类型变量列表
TypeVariable<?>[] typeVariables = clazz.getTypeParameters();
if (typeVariables != null && typeVariables.length > 0) {
for (int i = 0; i < typeVariables.length; i++) {
// 获取类型变量的注解数组,遍历解析
Annotation[] annotations = typeVariables[i].getAnnotations();
for (Annotation annotation : annotations) {
System.out.println("Annotation: " + annotation);
}

// 获取类型变量的边界数组
AnnotatedType[] annotatedBounds =
typeVariables[i].getAnnotatedBounds();
// default extends Object, so it's always true.
if (annotatedBounds != null && annotatedBounds.length > 0 ){
for (int j = 0; j < annotatedBounds.length; j++){
System.out.println("TypeVariable bounds: "
+ annotatedBounds[j].getType());
String boundName =
annotatedBounds[j].getType().getTypeName();
// 边界不是 Object,即显示指定了类型变量边界
if (!boundName.equals(Object.class.getTypeName())){
// 获取每个边界的注解数组
Annotation[] annotations1 =
annotatedBounds[j].getAnnotations();
// 遍历解析边界的所有注解
for (Annotation annotation : annotations1) {
System.out.println("Annotation: " + annotation);
}
}
}
}
}
}

// 解析当前类继承的父类
Class<?> superClass = clazz.getSuperclass();
// 确保父类不是 Object,即显示指定了 extends 父类
if (superClass != null && superClass != Object.class){
System.out.println("Super Class: " + superClass.getSimpleName());

// 获取父类的被注解类型
AnnotatedType annotatedSuperclass =
clazz.getAnnotatedSuperclass();
if (annotatedSuperclass != null) {
// 获取父类上的注解数组,并遍历解析
Annotation[] annotations =
annotatedSuperclass.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println("Annotation: " + annotation);
}
}
}

// 解析当前类实现的接口数组
//Class<?>[] interfaces = clazz.getInterfaces();
AnnotatedType[] annotatedTypes = clazz.getAnnotatedInterfaces();
if (annotatedTypes != null && annotatedTypes.length > 0) {
for (int i = 0; i < annotatedTypes.length; i++) {
// 接口名称
String interfaceName =
annotatedTypes[i].getType().getTypeName();
System.out.println("Implements interface: " + interfaceName);
// 获取每个接口的注解数组,并遍历解析注解
Annotation[] annotations =annotatedTypes[i].getAnnotations();
for (Annotation annotation : annotations){
System.out.println("Annotation: " + annotation);
appendAnnotation(builder, annotation);
}
}
}
}

// 递归解析 AnnotatedType 类型
private void recurseParsingAnnotatedType(AnnotatedType annotatedType){
// 被注解元素的类型
System.out.println("recurseParsingAnnotatedType: "
+ annotatedType.getType());
// 获取该元素上的注解数组,遍历解析
Annotation[] annotations = annotatedType.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println("Annotation: " + annotation);
}

if (annotatedType instanceof AnnotatedArrayType){
// 被注解元素是数组类型,必须递归,每次只能获取第一维的数组的注解
AnnotatedArrayType arrayType = (AnnotatedArrayType)annotatedType;
// 获取注解元素的数组原始类型
AnnotatedType genericComponentType =
arrayType.getAnnotatedGenericComponentType();
// genericComponentType 返回的注解只是第一维的,递归获取剩下的维度
recurseParsingAnnotatedType(genericComponentType);
} else if (annotatedType instanceof AnnotatedParameterizedType){
// 被注解元素是泛型
AnnotatedParameterizedType parameterizedType =
(AnnotatedParameterizedType) annotatedType;
// 获取泛型的参数列表
AnnotatedType[] annotatedTypes =
parameterizedType.getAnnotatedActualTypeArguments();
// 递归解析各个参数的注解类型
for (AnnotatedType type : annotatedTypes){
recurseParsingAnnotatedType(type);
}
} else if (annotatedType instanceof AnnotatedTypeVariable) {
// 被注解元素是类型变量
AnnotatedTypeVariable typeVariable =
(AnnotatedTypeVariable) annotatedType;
// 获取类型变量的边界
AnnotatedType[] typeBounds = typeVariable.getAnnotatedBounds();
// 递归解析类型变量的边界
for (AnnotatedType type : typeBounds){
recurseParsingAnnotatedType(type);
}
} else if (annotatedType instanceof AnnotatedWildcardType) {
// 被注解元素为泛型通配符
AnnotatedWildcardType wildcardType =
(AnnotatedWildcardType) annotatedType;
// 获取泛型通配符下界
AnnotatedType[] lowerBounds =
wildcardType.getAnnotatedLowerBounds();
// 递归解析边界
for (AnnotatedType type : lowerBounds){
recurseParsingAnnotatedType(type);
}
// 获取泛型通配符上界
AnnotatedType[] upperBounds =
wildcardType.getAnnotatedUpperBounds();
// 递归解析边界
for (AnnotatedType type : upperBounds){
recurseParsingAnnotatedType(type);
}
}
}

// 解析字段属性上的注解类型
private void parsingFields(){
// 获取当前类中所有字段属性
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields){
System.out.println("Field: " + field.toGenericString());
// 获取字段属性元素的被注解类型
AnnotatedType annotatedType = field.getAnnotatedType();
// 递归遍历解析该注解类型
recurseParsingAnnotatedType(annotatedType);
}
}

// 解析普通方法上的注解类型
private void parsingMethods(){
// 获取当前类中所有方法
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods){
System.out.println("Method: " + method.toGenericString());
// 获取方法的返回值注解类型,并递归解析该注解类型
AnnotatedType returnType = method.getAnnotatedReturnType();
recurseParsingAnnotatedType(returnType);

// 获取方法的参数列表数组,并递归解析数组的注解类型
AnnotatedType[] parameterTypes =
method.getAnnotatedParameterTypes();
for (AnnotatedType parameterType : parameterTypes) {
recurseParsingAnnotatedType(parameterType);
}

// 获取方法接收者注解类型,通常为定义该方法的类
AnnotatedType receiverType = method.getAnnotatedReceiverType();
// 遍历解析该注解类型
recurseParsingAnnotatedType(receiverType);

// 获取方法抛出的异常数组,并递归解析异常数组的注解类型
AnnotatedType[] exceptionTypes =
method.getAnnotatedExceptionTypes();
for (AnnotatedType exceptionType : exceptionTypes){
recurseParsingAnnotatedType(exceptionType);
}
}
}

public static void main(String[] args) {
TestGenericAnnotationParsingReflect parsingReflect
= new TestGenericAnnotationParsingReflect();
parsingReflect.parsingClass();
parsingReflect.parsingFields();
// parsingReflect.parsingConstructors();
parsingReflect.parsingMethods();
}
}

参考文档

0%