Перейти к основному содержимому

Получите аннотации поля с помощью отражения

· 3 мин. чтения

1. Обзор

В этом уроке мы узнаем, как получить аннотации поля. Кроме того, мы объясним, как работает мета-аннотация удержания. После этого мы покажем разницу между двумя методами, которые возвращают аннотации поля.

2. Политика хранения аннотации

Во-первых, давайте посмотрим на аннотацию Retention . Он определяет жизненный цикл аннотации. Эта мета-аннотация принимает атрибут RetentionPolicy . То есть атрибут определяет жизненный цикл , в котором аннотация видна:

  • RetentionPolicy.SOURCE — виден только в исходном коде
  • RetentionPolicy.CLASS — виден компилятору во время компиляции.
  • RetentionPolicy.RUNTIME — виден компилятору и среде выполнения.

Таким образом, только политика хранения RUNTIME позволяет нам программно читать аннотацию .

3. Получите аннотации поля с помощью отражения

Теперь давайте создадим пример класса с аннотированным полем. Мы определим три аннотации, из которых во время выполнения видны только две.

Первая аннотация видна во время выполнения:

@Retention(RetentionPolicy.RUNTIME)
public @interface FirstAnnotation {
}

Второй имеет такое же удержание:

@Retention(RetentionPolicy.RUNTIME)
public @interface SecondAnnotation {
}

Наконец, давайте создадим третью аннотацию, видимую только в исходном коде:

@Retention(RetentionPolicy.SOURCE)
public @interface ThirdAnnotation {
}

Теперь давайте определим класс с полем classMember, аннотированным всеми тремя нашими аннотациями:

public class ClassWithAnnotations {

@FirstAnnotation
@SecondAnnotation
@ThirdAnnotation
private String classMember;
}

После этого давайте получим все видимые аннотации во время выполнения. Мы будем использовать отражение Java , которое позволяет нам проверять атрибуты поля:

@Test
public void whenCallingGetDeclaredAnnotations_thenOnlyRuntimeAnnotationsAreAvailable() throws NoSuchFieldException {
Field classMemberField = ClassWithAnnotations.class.getDeclaredField("classMember");
Annotation[] annotations = classMemberField.getDeclaredAnnotations();
assertThat(annotations).hasSize(2);
}

В результате мы получили только две аннотации, доступные во время выполнения. Метод getDeclaredAnnotations возвращает массив нулевой длины, если в поле нет аннотаций.

Мы можем прочитать аннотации поля суперкласса таким же образом: получить поле суперкласса и вызвать тот же метод getDeclaredAnnotations .

4. Проверьте, аннотировано ли поле определенным типом

Давайте теперь посмотрим, как проверить, присутствует ли конкретная аннотация в поле. Класс Field имеет метод isAnnotationPresent , который возвращает значение true , если в элементе присутствует аннотация для указанного типа. Давайте проверим это на нашем поле classMember :

@Test
public void whenCallingIsAnnotationPresent_thenOnlyRuntimeAnnotationsAreAvailable() throws NoSuchFieldException {
Field classMemberField = ClassWithAnnotations.class.getDeclaredField("classMember");
assertThat(classMemberField.isAnnotationPresent(FirstAnnotation.class)).isTrue();
assertThat(classMemberField.isAnnotationPresent(SecondAnnotation.class)).isTrue();
assertThat(classMemberField.isAnnotationPresent(ThirdAnnotation.class)).isFalse();
}

Как и ожидалось, ThirdAnnotation отсутствует, поскольку для метааннотации Retention указана политика хранения SOURCE .

5. Полевые методы getAnnotations и getDeclaredAnnnotations

Давайте теперь посмотрим на два метода, предоставляемые классом Field , getAnnotations и getDeclaredAnnotations . Согласно Javadoc, метод getDeclaredAnnotations возвращает аннотации, непосредственно присутствующие в элементе . С другой стороны, Javadoc говорит для getAnnotations , что он возвращает все аннотации, присутствующие в элементе .

Поле в классе содержит аннотации непосредственно над его определением. В результате наследования аннотаций вообще не происходит. Все аннотации должны быть определены вместе с определением поля. Из-за этого методы getAnnotations и getDeclaredAnnotations всегда возвращают один и тот же результат .

Покажем это на простом тесте:

@Test
public void whenCallingGetDeclaredAnnotationsOrGetAnnotations_thenSameAnnotationsAreReturned() throws NoSuchFieldException {
Field classMemberField = ClassWithAnnotations.class.getDeclaredField("classMember");
Annotation[] declaredAnnotations = classMemberField.getDeclaredAnnotations();
Annotation[] annotations = classMemberField.getAnnotations();
assertThat(declaredAnnotations).containsExactly(annotations);
}

Более того, в классе Field мы можем обнаружить, что метод getAnnotations вызывает метод getDeclaredAnnotations :

@Override
public Annotation[] getAnnotations() {
return getDeclaredAnnotations();
}

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

В этой короткой статье мы объяснили роль метааннотаций политики хранения в получении аннотаций. Затем мы показали, как читать аннотации поля. Наконец, мы доказали, что для поля не существует наследования аннотаций.

Как всегда, исходный код примера доступен на GitHub .