GetDeclaredAnnotations: примеры (JAVA)
getDeclaredAnnotations: Annotation[]Описание метода getDeclaredAnnotations
Метод getDeclaredAnnotations() из интерфейса java.lang.reflect.AnnotatedElement возвращает массив аннотаций, непосредственно присутствующих на данном элементе (класс, метод, поле, конструктор, параметр и т. п.). Метод не принимает параметров и всегда возвращает массив типа java.lang.annotation.Annotation[]. Если аннотаций нет, возвращается пустой массив длины 0.
Ключевые особенности поведения:
- Возвращаются только аннотации, которые непосредственно объявлены на элементе. Аннотации, унаследованные через
@Inherited, не включаются в результат этого метода для классов. Для получения унаследованных аннотаций используетсяgetAnnotations(). - Аннотации с retention
RetentionPolicy.CLASSилиRetentionPolicy.SOURCEнедоступны через рефлексию во время выполнения; в результате они не появятся в возвращаемом массиве. - Если аннотация повторяемая (повторное применение
@Repeatable), вызовgetDeclaredAnnotations()вернёт либо контейнерную аннотацию, либо прокси-объекты, зависящие от способа компиляции; для получения всех повторов удобнее использоватьgetDeclaredAnnotationsByType(Class<T>)илиgetAnnotationsByType(Class<T>). - Возвращаемый массив - новая копия; модификация массива не влияет на метаданные класса.
Возвращаемые значения:
- Тип:
java.lang.annotation.Annotation[]. - Пустой массив при отсутствии аннотаций.
- При наличии аннотаций элементы массива представляют прокси-реализации соответствующих типов аннотаций.
Связанные методы интерфейса AnnotatedElement: getAnnotations(), getDeclaredAnnotation(Class<T>), getDeclaredAnnotationsByType(Class<T>), getAnnotationsByType(Class<T>), isAnnotationPresent(Class<? extends Annotation>). Эти методы полезны для уточнения поиска по типу аннотации и учета наследования.
Простые примеры использования
Ниже приведены небольшие примеры с выводом результата. Код и результат оформлены отдельно.
Пример 1: класс с одной аннотацией
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@interface A { String value() default "x"; }
@A("test")
class C {}
public class Demo1 {
public static void main(String[] args) {
java.lang.annotation.Annotation[] anns = C.class.getDeclaredAnnotations();
System.out.println(java.util.Arrays.toString(anns));
}
}
[ @A(value=test) ]
Пример 2: унаследованная аннотация и сравнение с getAnnotations()
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@interface Inh { }
@Inh
class Base { }
class Child extends Base { }
public class Demo2 {
public static void main(String[] args) {
System.out.println(java.util.Arrays.toString(Child.class.getDeclaredAnnotations()));
System.out.println(java.util.Arrays.toString(Child.class.getAnnotations()));
}
}
[] [ @Inh() ]
Пример 3: повторяемые аннотации и различие методов
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Tags.class)
@interface Tag { String value(); }
@Retention(RetentionPolicy.RUNTIME)
@interface Tags { Tag[] value(); }
@Tag("a")
@Tag("b")
class M {}
public class Demo3 {
public static void main(String[] args) {
System.out.println(java.util.Arrays.toString(M.class.getDeclaredAnnotations()));
System.out.println(java.util.Arrays.toString(M.class.getDeclaredAnnotationsByType(Tag.class)));
}
}
[ @Tags(value=[@Tag(value=a), @Tag(value=b)]) ] [ @Tag(value=a), @Tag(value=b) ]
Похожие методы в Java
Краткая сводка похожих методов и их особенностей:
getAnnotations()- возвращает аннотации, доступные с учетом наследования (через@Inherited) для классов; в отличие отgetDeclaredAnnotations()включает унаследованные.getDeclaredAnnotation(Class<T>)- возвращает первую найденную аннотацию указанного типа, если она непосредственно присутствует, илиnullиначе; удобнее, когда нужен конкретный тип.getDeclaredAnnotationsByType(Class<T>)- возвращает все аннотации данного типа, непосредственно присутствующие на элементе, с учетом поддержки@Repeatable.isAnnotationPresent(Class<? extends Annotation>)- быстрый булев проверочный метод, который учитывает наследование при вызовеisAnnotationPresentна классах.
Выбор зависит от цели: для полного списка прямых аннотаций - getDeclaredAnnotations(), для учета наследования - getAnnotations(), для получения всех экземпляров повторяемой аннотации - getDeclaredAnnotationsByType().
Аналоги в других языках
Краткое сравнение с аналогами в популярных языках и примеры.
- PHP (attributes, PHP 8+): механизм атрибутов предоставляет Runtime-методы через
ReflectionClass::getAttributes(). Отличие: в PHP атрибуты явные объекты-описания, возвращается массивReflectionAttribute. Пример:
<?
#[Attribute]
class A { public function __construct(public string $v) {} }
#[A("t")]
class C {}
$attrs = (new ReflectionClass(C::class))->getAttributes();
print_r($attrs);
?>
Array (
[0] => ReflectionAttribute Object (...)
)
- JavaScript / TypeScript: декораторы (experimental) могут добавлять метаданные через библиотеки (например reflect-metadata). Отличие: стандарт не встроен, требуется явное сохранение метаданных.
// TypeScript + reflect-metadata
import 'reflect-metadata';
function A(val: string) { return Reflect.metadata('a', val); }
@A('x')
class C {}
console.log(Reflect.getMetadata('a', C));
x
- Python: аннотации для параметров и возвращаемых значений хранятся в
__annotations__, а декораторы часто добавляют атрибуты к объектам. Отличие: нет стандартизированного механизма аннотаций как у Java, но декораторы дают гибкость.
def deco(func):
func._tag = 'x'
return func
@deco
def f(): pass
print(getattr(f, '_tag', None))
x
- C#: Reflection предоставляет
GetCustomAttributesиGetCustomAttributesData. Поведение похоже на Java, но тип возвращаемых объектов и механика доступа к значениям отличаются (AttributeInstance vs Annotation proxy).
using System;
[Obsolete("test")]
class C { }
class P { static void Main(){
var attrs = typeof(C).GetCustomAttributes(false);
Console.WriteLine(attrs.Length);
}}
1
- Go: теги полей структур доступны через
reflect.StructTagи методreflect.Type.Field(i).Tag.Get("key"). Отличие: аннотации представлены строками в тегах, не отдельными типами.
package main
import (
"fmt"
"reflect"
)
type S struct{ F int `json:"f" tag:"x"` }
func main(){
t := reflect.TypeOf(S{})
fmt.Println(t.Field(0).Tag.Get("tag"))
}
x
Вывод: у большинства языков есть механизмы метаданных, но форма, доступность во время выполнения и удобство работы отличаются. Java предоставляет строгую модель аннотаций с типами и прокси-объектами, что упрощает типобезопасный доступ к значениям.
Типичные ошибки и их причины
Ниже перечислены распространённые ошибки при работе с getDeclaredAnnotations() и способы диагностирования.
- Отсутствие аннотаций в результате вызова: чаще всего вызвано тем, что аннотация имеет
RetentionPolicy.CLASSилиSOURCE. Решение: установить@Retention(RetentionPolicy.RUNTIME)для доступа через рефлексию. - Ожидание унаследованных аннотаций:
getDeclaredAnnotations()не возвращает унаследованные аннотации. Для учета наследования использоватьgetAnnotations(). Пример показан в разделе примеров. - Проблемы с повторяемыми аннотациями: при использовании контейнерной аннотации вызов может вернуть контейнер, а не отдельные элементы. Для получения всех экземпляров применять методы
getDeclaredAnnotationsByType()/getAnnotationsByType(). - TypeNotPresentException или AnnotationFormatError: возможны, если аннотация или её элемент ссылаются на отсутствующий тип или недопустимый формат. В логах/стек-трейсе будет информация о причине; проверка classpath и корректности объявлений аннотаций поможет устранить проблему.
- AnnotationTypeMismatchException при обращении к значениям аннотации: возникает, если ожидаемый тип значения не совпадает с реальным (например, массив вместо одиночного значения). Причина часто в неверном объявлении аннотации или неправильной обработке прокси.
Пример ошибки из-за retention:
import java.lang.annotation.*;
@Retention(RetentionPolicy.CLASS)
@interface R { }
@R
class X {}
public class E { public static void main(String[] a){
System.out.println(X.class.getDeclaredAnnotations().length);
}}
0
Изменения в API и история
Ключевые изменения, связанные с работой аннотаций и методами интерфейса AnnotatedElement:
- В Java 5 (JDK 1.5) введена система аннотаций и базовые методы рефлексии для работы с ними, включая
getDeclaredAnnotations(). - В Java 8 добавлены методы, облегчающие работу с повторяемыми аннотациями:
getAnnotation(Class<T>),getDeclaredAnnotation(Class<T>),getAnnotationsByType(Class<T>),getDeclaredAnnotationsByType(Class<T>). Эти дополнения упростили обработку@Repeatable. - В более поздних релизах существенных изменений в семантике
getDeclaredAnnotations()не вносилось; развивались сопутствующие механизмы безопасности и оптимизации JVM, влияющие на производительность рефлексии.
Расширенные и редкие сценарии применения
Несколько подробных примеров с пояснениями и результатами.
1) Чтение значений аннотации с полем-типом Class и возможная ошибка при отсутствии типа в classpath
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@interface WithClass { Class<?> value(); }
@WithClass(String.class)
class A {}
public class Adv1 {
public static void main(String[] args) {
for (Annotation an : A.class.getDeclaredAnnotations()) {
System.out.println(an);
}
}
}
[ @WithClass(value=class java.lang.String) ]
Если в аннотации указывается класс, отсутствующий в classpath, при доступе к аннотации может возникнуть TypeNotPresentException (в старых версиях) или AnnotationFormatError. Это редкая ситуация, но полезная при диагностике проблем с загрузчиками классов.
2) Обработка повторяемых аннотаций на уровне методов и на параметрах
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Tags.class)
@interface Tag { String v(); }
@Retention(RetentionPolicy.RUNTIME)
@interface Tags { Tag[] value(); }
class X {
@Tag(v="a")
@Tag(v="b")
void m(@Tag(v="p") String s) {}
}
public class Adv2 {
public static void main(String[] args) throws Exception {
java.lang.reflect.Method mm = X.class.getDeclaredMethod("m", String.class);
System.out.println(java.util.Arrays.toString(mm.getDeclaredAnnotationsByType(Tag.class)));
java.lang.reflect.Parameter p = mm.getParameters()[0];
System.out.println(java.util.Arrays.toString(p.getDeclaredAnnotationsByType(Tag.class)));
}
}
[ @Tag(v=a), @Tag(v=b) ] [ @Tag(v=p) ]
Пояснение: для методов и параметров удобно использовать методы ...ByType, они всегда дают набор экземпляров указанного типа без необходимости вручную распаковывать контейнер.
3) Сканирование пакета и кеширование аннотаций (оптимизация)
// Упрощенный пример сканера
import java.lang.annotation.*;
import java.util.*;
@Retention(RetentionPolicy.RUNTIME)
@interface S { String v(); }
@S("c1") class C1 {}
@S("c2") class C2 {}
public class Scanner {
private final Map cache = new HashMap<>();
public Annotation[] getDeclared(Class<?> cl) {
return cache.computeIfAbsent(cl, k -> k.getDeclaredAnnotations());
}
public static void main(String[] a){
Scanner s = new Scanner();
System.out.println(Arrays.toString(s.getDeclared(C1.class)));
System.out.println(Arrays.toString(s.getDeclared(C2.class)));
}
}
[ @S(v=c1) ] [ @S(v=c2) ]
Пояснение: при массовой рефлексии имеет смысл кэшировать результаты getDeclaredAnnotations(), так как это уменьшает нагрузку на JVM при многократном обращении.
4) Обработка некорректных значений аннотации: пример с ожиданием массива, а получением одиночного значения
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@interface Arr { String[] v(); }
@Arr(v={"a","b"})
class B {}
public class Adv4 {
public static void main(String[] args) {
Arr a = B.class.getDeclaredAnnotation(Arr.class);
System.out.println(java.util.Arrays.toString(a.v()));
}
}
[a, b]
Пояснение: при несовпадении типов полей аннотации и кода обработки может появиться AnnotationTypeMismatchException. Проверка сигнатуры аннотации на этапе компиляции и аккуратная обработка в рантайме помогает избежать ошибок.
5) Доступ к аннотациям в условиях безопасности (SecurityManager)
В окружениях с ограниченным доступом к рефлексии могут быть ограничения на получение аннотаций; требуется учитывать политики безопасности и права для рефлексивных операций.
джава getDeclaredAnnotations function comments
- джава getDeclaredAnnotations - аргументы и возвращаемое значение
- Функция java getDeclaredAnnotations - описание
- getDeclaredAnnotations - примеры
- getDeclaredAnnotations - похожие методы на java
- getDeclaredAnnotations на javascript, c#, python, php
- getDeclaredAnnotations изменения java
- Примеры getDeclaredAnnotations на джава