Главная польза от механизма аннотаций — не в использовании уже готовых стандартных аннотаций в JDK. Но и нужда в создании собственной аннотации появляется нечасто. Например, если мы разрабатываем большую систему или выделяем отдельную библиотеку, то на архитектурном уровне реализация собственной аннотации точно принесет плоды.

Давай попробуем создать аннотацию.

Для этого создаем файл, и вместо class или interface пишем @interface. Это и будет файл нашей аннотации. По внутренней структуре аннотация схожа с интерфейсом.


public @interface Sum {
   int sum() default 0;
}

@interface указывает на то, что это аннотация,
default сообщает, что параметр по умолчанию будет возвращать определённое значение.

Мы создали аннотацию и теоретически уже можем ее использовать, но сначала лучше заняться ее конфигурированием.

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

Начнем с @Target.

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

@Target(ElementType.PACKAGE) для пакетов
@Target(ElementType.TYPE) для классов
@Target(ElementType.CONSTRUCTOR) для конструкторов
@Target(ElementType.METHOD) для методов
@Target(ElementType.FIELD) для атрибутов (переменных) класса
@Target(ElementType.PARAMATER) для параметров метода
@Target(ElementType.LOCAL_VARIABLE) для локальных переменных

Если нужна аннотация с несколькими типами, то можно передать несколько параметров в виде массива:


@Target({ ElementType.PARAMETER, ElementType.LOCAL_VARIABLE })

Следующий важный элемент конфигурации — аннотация @Retention.

Эта аннотация укажет, в каком жизненном цикле кода наша аннотация будет доступна:

RetentionPolicy.SOURCE Аннотации, аннотированные с помощью политики хранения SOURCE, отбрасываются во время выполнения.
RetentionPolicy.CLASS Аннотации, аннотированные с помощью политики хранения CLASS, записываются в файл .class, но удаляются во время выполнения.
RetentionPolicy.RUNTIME Аннотации, аннотированные с помощью политики хранения RUNTIME, сохраняются во время выполнения и могут быть доступны в нашей программе во время выполнения.

Также для конфигурации можно использовать еще несколько аннотаций:

Аннотация Значение
@Inherited Позволяет классу-наследнику реализовать наследование аннотаций родительского класса.
@Documented Аннотация будет помещена в сгенерированную документацию javadoc.

Вот теперь давай попробуем создать собственную аннотацию.

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


    @Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Info {
   String author() default "Author";
   String version() default "0.0";
}

Нашу аннотацию мы можем применять к методам и классам. Метаданные нашей аннотации будут доступны на этапе выполнения программы. Обрати внимание на параметры нашей аннотации. Мы можем вложить два параметра: имя и версию, но можем не класть, и тогда по умолчанию будут значения, которые мы указали (default "Author" и default "0.0").

Стоит отметить, что мы можем и не указывать дефолтное значение для параметров. В таком случае указание этого параметра становится обязательным.

При передаче параметров также обязательно указать параметр, который мы передаем через value = "value". Явное указание обязательно всегда, даже если параметр у аннотации единственный.

Применяем нашу аннотацию к нескольким классам:


@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() {}
}