1. Overview
1.概述
Annotations, a form of metadata which you can add to Java code. These annotations can be processed at compile time and embedded to class files or can be retained and accessed at runtime using Reflection.
注释,这是一种元数据形式,你可以将其添加到Java代码中。这些注释可以在编译时处理并嵌入到类文件中,或者可以保留并在运行时使用反思访问。
In this article, we will discuss how to change annotation value at runtime using Reflection. We will use class-level annotation for this example.
在这篇文章中,我们将讨论如何在运行时使用Reflection改变注释值。我们将在这个例子中使用类级注解。
2. Annotation
2.注释
Java allows creating new annotations using existing ones. In the simplest form, an annotation is represented as @ symbol followed by annotation name:
Java允许使用现有的注释创建新的注释。在最简单的形式中,一个注解被表示为@符号,后面是注解名称:
@Override
Let’s create our own annotation Greeter:
让我们创建我们自己的注释Greeter:
@Retention(RetentionPolicy.RUNTIME)
public @interface Greeter {
public String greet() default "";
}
Now, we will be creating a Java class Greetings which uses the class-level annotation:
现在,我们将创建一个Java类问候,它使用类级注解:。
@Greeter(greet="Good morning")
public class Greetings {}
Now, we will access annotation value using reflection. Java class Class provides a method getAnnotation to access annotations of a class:
现在,我们将使用反射访问注解值。Java类Class提供了一个方法getAnnotation来访问一个类的注释。
Greeter greetings = Greetings.class.getAnnotation(Greeter.class);
System.out.println("Hello there, " + greetings.greet() + " !!");
3. Alter Annotation
3.改动注释
Java class Class maintains a map for managing annotations – Annotation class as keys and Annotation object as value:
Java类类维护一个用于管理注释的地图 – Annotation类为键,Annotation对象为值:
Map<Class<? extends Annotation>, Annotation> map;
We will update this map to alter annotation at runtime. Approach to access this map differs in various JDK implementation. We will discuss it for JDK7 and JDK8.
我们将在运行时更新此地图以改变注释。访问该地图的方法在不同的JDK实现中有所不同。我们将讨论JDK7和JDK8的情况。
3.1. JDK 7 Implementation
3.1. JDK 7的实施
Java class Class has field annotations. As this is a private field, to access it, we have to set accessibility of the field to true. Java provides method getDeclaredField to access any field by its name:
Java类类有字段注释。由于这是一个私有字段,为了访问它,我们必须将该字段的可访问性设置为true。Java提供了方法getDeclaredField 通过其名称访问任何字段:
Field annotations = Class.class.getDeclaredField(ANNOTATIONS);
annotations.setAccessible(true);
Now, let’s get access to annotation map for class Greeter:
现在,让我们来访问Greeter类的注解图。
Map<Class<? extends Annotation>, Annotation> map = annotations.get(targetClass);
Now, this is the map which contains information about all annotations and their value object. We want to alter Greeter annotation value which we can achieve by updating annotation object of Greeter class:
现在,这是一张包含所有注解及其值对象信息的地图。我们想改变Greeter注解的值,我们可以通过更新Greeter类的注解对象来实现:。
map.put(targetAnnotation, targetValue);
3.2. JDK 8 Implementation
3.2. JDK 8实施
Java 8 implementations stores annotations information inside a class AnnotationData. We can access this object using the annotationData method. We will set accessibility for the annotationData method to true as it is a private method:
Java 8实现将注释信息存储在一个AnnotationData类中。我们可以使用annotationData方法访问这个对象。我们将把annotationData方法的可访问性设置为true,因为它是一个私有方法:。
Method method = Class.class.getDeclaredMethod(ANNOTATION_METHOD, null);
method.setAccessible(true);
Now, we can access annotations field. As this field also a private field, we will set accessibility to true:
现在,我们可以访问annotations字段。由于这个字段也是一个私有字段,我们将把可访问性设置为true:。
Field annotations = annotationData.getClass().getDeclaredField(ANNOTATIONS);
annotations.setAccessible(true);
This field has annotations cache map which stores annotation class and value object. Let’s alter that:
这个字段有注解缓存图,它存储了注解类和值对象。让我们改变一下:
Map<Class<? extends Annotation>, Annotation> map = annotations.get(annotationData);
map.put(targetAnnotation, targetValue);
4. Application
4.应用
Let’s take this example:
让我们来看看这个例子。
Greeter greetings = Greetings.class.getAnnotation(Greeter.class);
System.err.println("Hello there, " + greetings.greet() + " !!");
This will be greeting “Good morning” as that is the value we provided to annotation.
Now, we will create one more object of Greeter type with value as “Good evening”:
这将是 “早上好 “的问候语,因为这是我们提供给注释的值。
现在,我们将再创建一个Greeter类型的对象,其值为 “晚上好”。
Greeter targetValue = new DynamicGreeter("Good evening");
Let’s update the annotation map with the new value:
让我们用新的值来更新注释图。
alterAnnotationValueJDK8(Greetings.class, Greeter.class, targetValue);
Let’s check greeting value again:
让我们再检查一下问候语的价值。
greetings = Greetings.class.getAnnotation(Greeter.class);
System.err.println("Hello there, " + greetings.greet() + " !!");
It will greet as “Good evening”.
它将问候 “晚上好”。
5. Conclusion
5.总结
Java implementations use two data field to store annotation data: annotations, declaredAnnotations. The difference between these two: first store annotations from parent classes also and later one stores only for current class.
Java实现使用两个数据域来存储注释数据。annotations,declaredAnnotations。这两者之间的区别是:前者也存储来自父类的注释,后者只存储当前类的注释。
As the implementation of getAnnotation differs in JDK 7 and JDK 8, we using here annotations field map for simplicity.
由于getAnnotation在JDK 7和JDK 8中有所不同,我们在这里使用annotationsfield map来简化操作。
And, as always, the source code of implementation is available over on Github.
而且,像往常一样,实施的源代码可以在Github上获得。