Hello, annotations!

Главное что нужно знать об аннотациях — они ничего не делают! Аннотации представляют собой простые метки в коде и больше ничего. Когда кто-то говорит «Аннотация @DoSomething делает блаблабла» это фактически означает, что кто-то где-то вызывает код, который находит типы с этой аннотацией и делает блаблабла.

Зачем нужны аннотации? Они позволяют разработчику декларировать дополнительные свойства кода, который он пишет. Говоря простыми словами — когда разработчик пишет над определением метода  @Test это означает две вещи:

  1. Разработчик говорит себе и всему миру: «Этот метод не предназначен для использования в коде, этот метод реализует какую-то проверку и должен вызываться только во время исполнения тестов»
  2. Тестовый фреймворк осматривает все доступные ему методы в тестовых классах и запускает все методы, которые имеют аннотацию @Test

Другой хороший пример пользы от аннотаций был в статье, рассказывающей о разрешении конфликтов при внедрении зависимостей: некоторой аннотацией (можно считать, что именем) помечался как внедряемый класс, так и переменные, в которые он внедрялся.

Подготовка

Нам понадобится пустой maven проект с JUnit и Hamcrest:

И класс приветствия:

 

Собственная аннотация

Сделать аннотацию самому не сложно — аннотация состоит из имени, свойств и конфигурации:

@Target(ElementType.FIELD)  говорит, что эта аннотация может быть применена только к полям классов. Аннотации можно применять к пакетам, классам и их конструкторам, методам и их аргументам, переменным и так далее. @Retention(RetentionPolicy.RUNTIME) делает аннотацию доступной во время исполнения, а не удаляет её во время компиляции.

@interface говорит, что это аннотация, а не обычный интерфейс. Внутри аннотации могут быть определены её свойства, но их определение несколько необычно: во первых они выглядят как методы, во вторых у них может быть значение по умолчанию.

Использование аннотации очевидно:

В первом случае значением свойства value будет значение по умолчанию: «world», во втором «», а в третьем … таки да, «». У свойства по имено value() если удобное соглашение, именно в него попадает значение аннотации по умолчанию.

Использовать аннотацию гораздо сложнее. Так как аннотации относятся к коду, а не к данным программы, то для доступа к ним приходиться использовать reflection:

Вначале надо получить аннотируемый объект, потом получить из него аннотацию и, наконец, взять у аннотации её значения. Другой пример показывает, что никакой другой связи между кодом и аннотациями нет:

Код примера доступен на github