Аннотации в Java предоставляют лишь информацию о коде и не имеют прямого влияния на сам код. В этом руководстве мы узнаем следующее: как пишут аннотаций; как используют аннотации и как парсить аннотации с помощью рефлексии.
Создание пользовательских аннотаций в Java
Создание пользовательских аннотаций в Java очень похоже на создание интерфейса, только вот само ключевое слово interface пишется со знаком @. Давайте посмотрим пример аннотации, а затем мы обсудим его функции.
MInfo.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
package ua.com.prologistic; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Documented @Target(ElementType.METHOD) @Inherited @Retention(RetentionPolicy.RUNTIME) public @interface MethodInfo{ String author() default "Andrew"; String date(); int revision() default 1; String comments(); } |
- Методы в пользовательской аннотации должны быть без параметров.
- Методы в пользовательской аннотации могут возвращать лишь примитивы, String, Перечисления (Enums), аннотации.
- Методы в пользовательской аннотации могут иметь значения по умолчанию.
- Аннотации могут иметь мета-аннотации, прикрепленные к ним. Мета аннотации используются для предоставления информации об аннотации. Есть четыре типа мета-аннотаций:
@Documented
— указывает, что элементы, использующие эту аннотацию должны быть задокументированы в Javadoc и аналогичных инструментах.@Target
— указывает виды элементов программы, к которым применим тип аннотации. Возможные значения: TYPE, METHOD, CONSTRUCTOR, FIELD и т.д. Если мета-аннотация @Target не используется, то аннотация может быть использована в любом элементе программы.@Inherited
— указывает, что тип аннотации автоматически передается по наследству. Если пользователь запрашивает тип аннотации на объявление класса, а объявление класса не имеет аннотацию для этого типа, то суперкласс класса будет автоматически запрошен для типа аннотации. Этот процесс будет повторяться до тех пор, пока аннотация для этого типа не будь найдена или будет достигнута верхняя часть иерархии классов (Object).@Retention
— указывает, как долго сохранять аннотации с аннотированными типами. Этим занимается аргумент RetentionPolicy, для которого можно использовать значения SOURCE, CLASS или RUNTIME.
Встроенные в Java аннотации
В Java используется 3 встроенные аннотации:
@Override
— когда мы хотим переопределить метод суперкласса, мы должны использовать эту аннотацию — это сообщит компилятору, что мы переопределили метод. Поэтому, когда метод суперкласса будет удален или изменен, компилятор выдаст сообщение об ошибке. Очень важно всегда использовать аннотацию @Override при переопределении метода.@Deprecated
— когда мы хотим сообщить компилятору то, что метод является устаревшим, мы должны использовать эту аннотацию. Документация по Java рекомендует предоставлять компилятору информацию о том, почему этот метод является устаревшим и какой метод следует использовать вместо него в Javadoc.@SuppressWarnings
— это простой способ попросить компилятор игнорировать конкретные предупреждения, если они вдруг появятся.
Давайте посмотрим пример, показывающий использование встроенных в Java аннотаций, а также использование аннотаций, созданных нами в примере выше.
AnnotationExampleClass.java
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 |
package ua.com.prologistic; import java.io.FileNotFoundException; import java.util.ArrayList; import java.util.List; public class AnnotationExampleClass { public static void main(String[] args) { } @Override @MethodInfo(author = "Andrew", comments = "Main method", date = "Aug 10 2015", revision = 1) public String toString() { return "Переопределили метод toString() "; } @Deprecated @MethodInfo(comments = "устаревший метод", date = "Aug 10 2015") public static void oldMethod() { System.out.println("Этот метод не стоит дальше использовать"); } @SuppressWarnings({ "unchecked", "deprecation" }) @MethodInfo(author = "Andrew", comments = "Main method", date = "Aug 10 2015", revision = 4) public static void genericsTest() throws FileNotFoundException { List l = new ArrayList(); l.add("фыва"); oldMethod(); } } |
Парсинг Java аннотаций
Мы будем использовать Reflection (рефлексию) для анализа Java-аннотаций. Обратите внимание, что политика сохранения аннотаций должна быть RUNTIME, в противном случае информация не будет доступна для парсинга во время выполнения и мы не сможем извлечь какие-либо данные.
AnnotationParsingClass.java
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 |
package ua.com.prologistic; import java.lang.annotation.Annotation; import java.lang.reflect.Method; public class AnnotationParsingClass { public static void main(String[] args) { try { for (Method method : AnnotationParsingClass.class .getClassLoader() .loadClass(("ua.com.prologistic.AnnotationExampleClass")) .getMethods()) { // проверяем, присутствует ли аннотация MInfo в методе if (method.isAnnotationPresent(ua.com.prologistic.MInfo.class)) { try { // проходим по всем доступным аннотациям в методе for (Annotation annot : method.getDeclaredAnnotations()) { System.out.println("Аннотация в методе '" + method + "' : " + annot); } MInfo methodAnno = method .getAnnotation(MInfo.class); if (methodAnno.revision() == 1) { System.out.println("Метод с ревизией номер 1 = " + method); } } catch (Throwable ex) { ex.printStackTrace(); } } } } catch (SecurityException | ClassNotFoundException e) { e.printStackTrace(); } } } |
Результат выполнения приведенной выше программы:
1 2 3 4 5 6 |
Аннотация в методе 'public java.lang.String ua.com.prologistic.AnnotationExampleClass.toString()' : @ua.com.prologistic.MInfo(author=Andrew, revision=1, comments=Main method, date=Aug 10 2015) Метод с ревизией номер 1 = public java.lang.String ua.com.prologistic.AnnotationExampleClass.toString() Аннотация в методе 'public static void ua.com.prologistic.AnnotationExampleClass.oldMethod()' : @java.lang.Deprecated() Аннотация в методе 'public static void ua.com.prologistic.AnnotationExampleClass.oldMethod()' : @ua.com.prologistic.MInfo(author=Andrew, revision=1, comments=устаревший метод, date=Aug 10 2015) Метод с ревизией номер 1 = public static void ua.com.prologistic.AnnotationExampleClass.oldMethod() Аннотация в методе 'public static void ua.com.prologistic.AnnotationExampleClass.genericsTest() throws java.io.FileNotFoundException' : @ua.com.prologistic.MInfo(author=Andrew, revision=3, comments=Main method, date=Aug 10 2015) |
Reflection API является очень мощным инструментом и очень часто используется в Java, J2EE фреймворках (Spring, Hibernate, JUnit и многих других).
Вот и закончилось небольшое руководство по аннотациям в Java. Следите за обновлениями на сайте.