Создание аннотаций — процесс довольно простой, хоть и ограниченый некоторыми правилами. Теперь нам нужно разобраться, в чем их польза на практике.
Давай вспомним, как мы создаем свою аннотацию.
Пишем аннотацию, которая будет аннотировать классы и методы и содержать информацию об авторе и версии:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Info {
String author() default "Author";
String version() default "0.0";
}
Наши классы, к которым мы добавили аннотацию:
@Info
public class MyClass1 {
@Info
public void myClassMethod() {}
}
@Info(version = "2.0")
public class MyClass2 {
@Info(author = "Anonymous")
public void myClassMethod() {}
}
@Info(author = "Anonymous", version = "2.0")
public class MyClass3 {
@Info(author = "Anonymous", version = "4.0")
public void myClassMethod() {}
}
Как же нам воспользоваться этими данными на этапе работы программы?
Извлечь метаданные из аннотаций можно с помощью рефлексии. Вспомним, что такое рефлексия. Это механизм исследования данных о программе во время ее выполнения. Рефлексия позволяет получать информацию о полях, методах, конструкторах классов, а также о классах.
С помощью рефлексии мы прочитаем аннотации в классе и выведем необходимую нами информацию.
Распознаем данные из наших классов в main:
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
public class Main {
public static void main(String[] args) throws NoSuchMethodException {
readMyClass(MyClass1.class);
readMyClass(MyClass2.class);
readMyClass(MyClass3.class);
}
static void readMyClass(Class<?> myClassObj) throws NoSuchMethodException {
System.out.println("\nКласс " + myClassObj.getName());
readAnnotation(myClassObj);
Method method = myClassObj.getMethod("myClassMethod");
readAnnotation(method);
}
static void readAnnotation(AnnotatedElement element) {
try {
System.out.println("Поиск аннотаций в " + element.getClass().getName());
Annotation[] annotations = element.getAnnotations();
for (Annotation annotation : annotations) {
if (annotation instanceof Info) {
final Info fileInfo = (Info) annotation;
System.out.println("Автор: " + fileInfo.author());
System.out.println("Версия: " + fileInfo.version());
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
В метод readMyClass мы передаем экземпляр нашего класса на обработку.
Далее в метод readAnnotation мы можем передать как класс, так и метод. Так и поступим: передаем туда объект класса и объект метода. Принимается объект, который реализует контракт AnnotatedElement. Это позволяет достать из него список аннотаций и прочитать информацию по каждой из них.
Обрати внимание на то, что мы не достанем информацию, не проверив принадлежность аннотации к нашему типу аннотации (if (annotation instanceof Info)).
На выходе мы получаем полную информацию из аннотаций:
Поиск аннотаций в java.lang.Class
Автор: Author
Версия: 0.0
Поиск аннотаций в java.lang.reflect.Method
Автор: Author
Версия: 0.0
Класс annotation.MyClass2
Поиск аннотаций в java.lang.Class
Автор: Author
Версия: 2.0
Поиск аннотаций в java.lang.reflect.Method
Автор: Anonymous
Версия: 0.0
Класс annotation.MyClass3
Поиск аннотаций в java.lang.Class
Автор: Anonymous
Версия: 2.0
Поиск аннотаций в java.lang.reflect.Method
Автор: Anonymous
Версия: 4.0
Так с помощью рефлексии мы смогли извлечь метаинформацию.
Теперь рассмотрим пример использования аннотаций для усовершенствования кода, в том числе повышения читаемости, скорости роботы и качества в целом. В этом нам поможет Lombok.
Lombok — это плагин-надстройка компилятора, который с помощью ключевых слов-аннотаций скрывает огромное количество кода, расширяя язык и тем самым упрощая разработку и добавляя некоторую функциональность.
Рассмотрим пример аннотаций из Lombok:
@ToString | Генерирует реализацию для метода toString(), которая состоит из аккуратного представления объекта: имя класса, все поля и их значения. |
|
@EqualsAndHashCode | Генерирует реализации equals и hashCode, которые по умолчанию используют нестатические и нестационарные поля, но настраиваются. | Подробнее можно прочитать на сайте проекта. Там описан пример с использованием @EqualsAndHashCode и без него со стандартной реализацией. |
@Getter / @Setter | Генерирует геттеры и сеттеры для частных полей. |
|
@NonNull | Используются для утверждения, что поля не являются null при создании экземпляра объекта. Иначе выбрасывается исключение NullPointerException. |
|
У Lombok есть еще много полезных аннотаций, которые используются реже. Мы рассмотрели простую часть его аннотаций. Про сам проект можно почитать больше на официальном сайте.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ