Еще одна новая возможность, появившаяся в версии JDK 8, позволяет повторять аннотации в одном и том же элементе.
Такие аннотации называются повторяющимися. Для того чтобы сделать аннотацию повторяющейся, ее следует снабдить аннотацией @Repeatable, определенной в пакете java.lang.annotation.
В ее поле value указывается тип контейнера для повторяющейся аннотации. Такой контейнер указывается в виде аннотации, для которой поле value является массивом типа повторяющейся аннотации.
Следовательно, чтобы сделать аннотацию повторяющейся, прежде нужно создать контейнерную аннотацию, а затем указать ее тип в качестве аргумента аннотации @Repeatable.
Для доступа к повторяющимся аннотациями с помощью такого метода, как, например, getAnnotation(), следует воспользоваться контейнерной, а не самой повторяющейся аннотацией.
Именно такой подход и демонстрируется в приведенном ниже примере программы. В этой программе MyAnno преобразуется в повторяющуюся аннотацию, а затем демонстрируется ее применение.
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 |
// Продемонстрировать применение повторяющейся аннотации import java.lang.annotation.*; import java.lang.reflect.*; // сделать аннотацию MyAnno повторяющейся @Retention(RetentionPolicy.RUNTIME) @Repeatable(MyRepeatedAnnos.class) @interface MyAnno { String str() default "Тестирование"; int val() default 9000; } // Это контейнерная аннотация @Retention(RetentionPolicy.RUNTIME) @interface MyRepeatedAnnos { MyAnno[] value(); } class RepeatAnno { // повторить аннотацию MyAnno в методе myMeth() @MyAnno(str = "Первая аннотация", val = -1) @MyAnno(str = "Вторая аннотация", val = 100) public static void myMeth(String str, int i) { RepeatAnno ob = new RepeatAnno(); try { Class <?> c = ob.getClass(); // получить аннотации для метода myMeth() Method m = c.getMethod("myMeth", String.class, int.class); // вывести повторяющиеся аннотации MyAnno Annotation anno = m.getAnnotation(MyRepeatedAnnos.class); System.out.println(anno); } catch (NoSuchMethodException exc) { System.out.println("Метод не найден."); } } public static void main(String args[]) { myMeth("тест", 10); } } |
Ниже приведен результат, выводимый данной программой:
1 2 3 4 5 |
pro-java.ru@admin:~$ javac reflection.java pro-java.ru@admin:~$ java RepeatAnno @MyRepeatedAnnos(value=[@MyAnno(val=-1, str=Первая аннотация), @MyAnno(val=100, str=Вторая аннотация)]) pro-java.ru@admin:~$ |
Как пояснялось ранее, чтобы сделать аннотацию MyAnno повторяющейся, ее нужно снабдить аннотацией @Repeatаble, указывающей ее контейнерную аннотацию, которая называется MyRepeatedAnnos.
В данной программе для доступа к повторяющимся аннотациям вызывается метод getAnnotation(), которому передается класс контейнерной аннотации, а не самой повторяющейся аннотации.
Как следует из результата выполнения данной программы, повторяющиеся аннотации разделяются запятой. Они не возвращаются по отдельности.
Еще один способ получить повторяющиеся аннотации состоит в том, чтобы воспользоваться одним из новых методов, оперирующих непосредственно повторяющейся аннотацией и внедренных в интерфейс AnnotatedElement в версии JDК 8.
Это методы getAnnotationsByType() и getDeclaredAnnotationsByТуре(). Ниже приведена общая форма первого из этих методов.
1 |
<T extends Annotation> T[] getAnnotationByType(Class<T> тип_аннотации) |
Этот метод возвращает массив аннотаций, имеющих тип_аннотации и связанных с вызывающим объектом. Если же аннотации отсутствуют, этот массив будет иметь нулевую длину.
Вы в курсе что существует такой софт как After Effects от компании Adobe? Авторы твердят что именно аннотации помогли им сэкономить время на разработку софта.
After Effects является одним из лучшим софтом для создания видео роликов. Например, если у вас есть собственный хостинг и желаете его рекламировать то сможете с легкостью скачать такой видео-шаблон как Web Hosting Explainer и делать из него все угодно.
Подробную информацию сможете найти на известном проекте hunterae.com.
Ниже приведен пример применения метода getAnnotationsByType() для получения повторяющихся аннотаций MyAnno, представленных в предыдущем примере программы:
1 2 3 4 |
Annotation[] annos = m.getAnnotationsByType(MyAnno.class); for(Annotation a : annos) { System.out.println(a); } |
В данном примере тип повторяющейся аннотации MyAnno передается методу getAnnotationsByType().
Возвращаемый в итоге массив содержит все экземпляры аннотации MyAnno, связанные с методом myMeth() (в данном примере их два).
Каждая повторяющаяся аннотация доступна в массиве по индексу. В данном случае каждая аннотация MyAnno выводится при выполнении цикла в стиле for each.
Существует ряд ограничений, накладываемых на объявления аннотаций. Во первых, одна аннотация не может наследовать другую.
Во-вторых, все методы, объявленные в аннотации, должны быть без параметров. Кроме того, они должны возвращать один из перечисленных ниже типов:
- примитивный тип наподобие int или double;
- объект класса String или Class;
- перечислимый тип;
- тип другой аннотации;
- массив одного из предыдущих типов.
Аннотации не могут быть обобщенными. Иными словами, они не могут принимать параметры типа. И наконец, при объявлении методов в аннотациях нельзя указывать оператор throws.