Изменение параметров аннотации во время выполнения

Изменение параметров аннотации во время выполнения

1. обзор

Annotations, форма метаданных, которые вы можете добавить в код Java. Это сканированиеannotations обрабатывается во время компиляции и внедряется в файлы классов или может быть сохранено и доступно во время выполнения с помощьюReflection.

В этой статье мы обсудим, как изменить значениеannotation во время выполнения, используяReflection. Мы будем использовать аннотацию на уровне класса для этого примера.

2. аннотирование

Java позволяет создавать новыеannotations, используя существующие. В простейшей форме аннотация представлена ​​как символ@, за которым следует имя аннотации:

@Override

Давайте создадим нашу собственную аннотациюGreeter:

@Retention(RetentionPolicy.RUNTIME)
public @interface Greeter {
    public String greet() default "";
}

Теперь мы будем создавать Java-классGreetings, который используетannotation: уровня класса

@Greeter(greet="Good morning")
public class Greetings {}

Теперь мы получим доступ к значению аннотации с помощью отражения. Класс JavaClass предоставляет методgetAnnotation для доступа к аннотациям класса:

Greeter greetings = Greetings.class.getAnnotation(Greeter.class);
System.out.println("Hello there, " + greetings.greet() + " !!");

3. Изменить аннотацию

Класс JavaClass поддерживает карту для управления аннотациями - классAnnotation как ключи и объектAnnotation как значение:

Map, Annotation> map;

Мы обновим эту карту, чтобы изменить аннотацию во время выполнения. Подход к доступу к этой карте отличается в различных реализациях JDK. Мы обсудим это для JDK7 и JDK8.

3.1. Реализация JDK 7

Класс JavaClass поле shasannotations. Поскольку это частное поле, для доступа к нему мы должны установить доступность поля наtrue. Java предоставляет методgetDeclaredField to для доступа к любому полю по его имени:

Field annotations = Class.class.getDeclaredField(ANNOTATIONS);
annotations.setAccessible(true);

Теперь давайте получим доступ к карте аннотаций для классаGreeter:

 Map, Annotation> map = annotations.get(targetClass);

Теперь это карта, которая содержит информацию обо всех аннотациях и их значении объекта. Мы хотим изменить значение аннотацииGreeter, чего мы можем достичь, обновив объект аннотации классаGreeter:

map.put(targetAnnotation, targetValue);

3.2. Реализация JDK 8

Реализации Java 8 хранят информациюannotations внутри классаAnnotationData. Мы можем получить доступ к этому объекту с помощью методаannotationData. Мы установим доступность для методаannotationData наtrue, поскольку это частный метод:

Method method = Class.class.getDeclaredMethod(ANNOTATION_METHOD, null);
method.setAccessible(true);

Теперь у нас есть доступ к полюannotations. Поскольку это поле также является частным полем, мы установим доступность наtrue:

Field annotations = annotationData.getClass().getDeclaredField(ANNOTATIONS);
annotations.setAccessible(true);

Это поле имеет карту кэша аннотаций, в которой хранятся класс аннотаций и объект значения. Давайте изменим это:

Map, Annotation> map = annotations.get(annotationData);
map.put(targetAnnotation, targetValue);

4. заявка

Возьмем такой пример:

Greeter greetings = Greetings.class.getAnnotation(Greeter.class);
System.err.println("Hello there, " + greetings.greet() + " !!");

Это будет приветствие «Доброе утро», так как это значение, которое мы предоставили для аннотации. Теперь создадим еще один объект типаGreeter со значением «Добрый вечер»:

Greeter targetValue = new DynamicGreeter("Good evening");

Давайте обновим карту аннотаций новым значением:

alterAnnotationValueJDK8(Greetings.class, Greeter.class, targetValue);

Давайте еще раз проверим значение приветствия:

greetings = Greetings.class.getAnnotation(Greeter.class);
System.err.println("Hello there, " + greetings.greet() + " !!");

Это будет приветствовать как «Добрый вечер».

5. Заключение

Реализации Java используют два поля данных для хранения данных аннотации:annotations,declaredAnnotations. Разница между этими двумя: сначала хранятся аннотации от родительских классов, а затем - только для текущего класса.

Поскольку реализацияgetAnnotation отличается в JDK 7 и JDK 8, мы используем здесь карту поляannotations для простоты.

И, как всегда, доступен исходный код реализацииover on Github.