Java base class annotation

Аннотации в JAVA: обзор синтаксиса и создание собственных

Статья ориентирована больше на новичков, или тех, кто еще не работал с данным механизмом в языке. Я постараюсь рассказать, что это такое, зачем они нужны, и как можно самому создавать удобные для себя аннотации.

Аннотации представляют из себя дескрипторы, включаемые в текст программы, и используются для хранения метаданных программного кода, необходимых на разных этапах жизненного цикла программы.
Информация, хранимая в аннотациях, может использоваться соответствующими обработчиками для создания необходимых вспомогательных файлов или для маркировки классов, полей и т.д.

Синтаксис

Аннотация задается описанием соответствующего интерфейса.
Например так:

import java.lang.annotation.*; @Target(value=ElementType.FIELD) @Retention(value= RetentionPolicy.RUNTIME) public @interface Name

Как видно из примера выше, аннотация определяется описанием с ключевым словом interface и может включать в себя несколько полей, которые можно задать как обязательными, так и не обязательными. В последнем случае подставляется default значение поля.
Также из примера видно, что саму аннотацию можно пометить несколькими аннотациями.
Разберемся для начала, чем можно пометить собственную аннотацию, и зачем.

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

Аннотация @Target указывает, что именно мы можем пометить этой аннотацией, это может быть поле, метод, тип и т.д.

Аннотация @Documentedуказывает, что помеченная таким образом аннотация должна быть добавлена в javadoc поля/метода и т.д.
Например, класс, помеченный аннотацией без @Documented, будет выглядеть так:

public class TestClass extends java.lang.Object

А если в описание аннотации добавить @Documented, получим:

@ControlledObject(name="name") public class TestClass extends java.lang.Object

Аннотация @Inherited помечает аннотацию, которая будет унаследована потомком класса, отмеченного такой аннотацией.
Сделаем для примера пару аннотаций и пометим ими класс.

@Inherited @interface PublicAnnotate < >@interface PrivateAnnotate < >@PublicAnnotate @PrivateAnnotate class ParentClass < >class ChildClass extends ParentClass

Класс ChildClass унаследует от родительского класса только аннотацию PublicAnnotate.

Пример своей аннотации.

Попробуем теперь написать рабочий пример с использованием аннотаций.
Представим себе, что у нас есть какой-то самодельный проект, который на вход получает класс, специально заанотированный, чтобы проект мог управлять жизненным циклом объектов этого класса, и пусть там будут аннотации StartObject, StopObject для описания методов класса, и ControlledObject для описания самого класса. Последней аннотации дадим еще поле name, путь там хранится якобы имя для поиска.
Аннотации будут выглядеть так:

@Target(value=ElementType.METHOD) @Retention(value= RetentionPolicy.RUNTIME) public @interface StartObject < >@Target(value=ElementType.METHOD) @Retention(value= RetentionPolicy.RUNTIME) public @interface StopObject < >@Target(value=ElementType.TYPE) @Retention(value= RetentionPolicy.RUNTIME) public @interface ControlledObject

Напишем модуль, проверяющий подходит ли класс для загрузки в наш гипотетический проект или нет.
Сперва определим сам проверяемый класс.

@ControlledObject(name="biscuits") public class Cookies < @StartObject public void createCookie()< //бизнес логика >@StopObject public void stopCookie() < //бизнес логика >>

Для того, чтобы работать с классом, сначала необходимо загрузить класс в контекст приложения. Используем:
Class cl = Class.forName(«org.annotate.test.classes.Cookies»);
Далее, через механизм reflection мы получаем доступ к полям и аннотациям класса.
Проверим наличие аннотированных методов в классе и аннотации на самом классе:

if(!cl.isAnnotationPresent(ControlledObject.class)) < System.err.println("no annotation"); >else < System.out.println("class annotated ; name - " + cl.getAnnotation(ControlledObject.class)); >boolean hasStart=false; boolean hasStop=false; Method[] method = cl.getMethods(); for(Method md: method) < if(md.isAnnotationPresent(StartObject.class)) if(md.isAnnotationPresent(StopObject.class)) if(hasStart && hasStop) > System.out.println("Start annotaton - " + hasStart + "; Stop annotation - " + hasStop ); 

Запустив, на выходе мы получим:
Start annotaton — true; Stop annotation — true.
Если попробовать убрать одну из аннотаций, то вывод сообщит о несоответствии требованиям.

Читайте также:  Xmlhttprequest post data php
Итог

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

Подробнее ознакомиться с данным механизмом могу порекомендовать в книге «Java 2. Библиотека профессионала, том 2. Тонкости программирования» Кей С. Хорстманна, Гари Корнелла, или на сайте oracle, где так же есть подробные туториалы.

Источник

Аннотации в JAVA

Аннотации — это форма метаданных. Они предоставляют информацию о программе, при том сами частью программы не являются.

Применение

  • Информация для компилятора. Могут использоваться компилятором для обнаружения ошибок и подавления предупреждений.
  • Обработка во время компиляции и развертывания. Программа может создавать код, XML-файлы и т.п. на основе аннотаций.
  • Обработка во время выполнения. Некоторые аннотации могут использоваться во время выполнения программы.

Синтаксис

Начинаются с @ , могут включать элементы, которым присваиваются значения:

@Author( name = "Benjamin Franklin" date = "3/27/2003" ) class MyClass

Если такой элемент один, его имя можно опустить:

@SupressWarnings("unchecked") void MyMethod()

Если таких элементов нет, можно опустить скобки. Можно использовать несколько аннотаций в одном объявлении:

@Author(name = "Jane Doe") @EBook class MyClass

Аннотации могут быть повторяющимися.

@Author(name = "Jane Doe") @Author(name = "John Smith") class MyClass

Где в коде можно использовать аннотации

Аннотации применяются с объявлениями классов, полей и других элементов программы.

Аннотации, использующиеся с типами, называются аннотациями типов. Примеры таких аннотаций:

myString = (@NonNull String) str;

class UnmodifiableList implements @Readonly List

void monitorTemperature() throws @Critical TemperatureException

Создание аннотации

Синтаксис

Описание аннотации напоминает описание интерфейса. Оно начинается с @Interface , а его элементы похожи на методы, которые могут иметь дефолтные значения.

Читайте также:  Php call closure object

Пример

Допустим, в какой-то IT-компании тела всех классов начинаются с комментариев, содержащих важную информацию:

public class Generation3List extends Generation2List < // Author: John Doe // Date: 3/17/2002 // Current revision: 6 // Last modified: 4/12/2004 // By: Jane Doe // Reviewers: Alice, Bill, Cindy // class code goes here >

Описание аннотации, которая заменит комментарии:

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

@ClassPreamble ( author = "John Doe", date = "3/17/2002", currentRevision = 6, lastModified = "4/12/2004", lastModifiedBy = "Jane Doe", reviewers = ) public class Generation3List extends Generation2List

Замечание: для добавления аннотации в Javadocs нужно использовать @Documented:

import java.lang.annotation.*; @Documented @interface ClassPreamble < // Описание элементов аннотации >

Предопределенные аннотации

В Java есть аннотации, описанные заранее. Часть из них предоставляют информацию для компилятора, часть применяется к другим аннотациям.

Аннотации, использующиеся компилятором

Располагаются в пакете java.lang.

Помеченный этой аннотацией элемент устарел и больше не должен использоваться (это стоит отметить в Javadoc). При наличии такого элемента в программе компилятор сгенерирует предупреждение.

// Комментарий Javadoc: /** * @deprecated * объяснение, почему метод устарел. */ @Deprecated static void deprecatedMethod()

Информирует компилятор о том, что аннотируемый элемент должен переопределять элемент родительского класса. При некорректном переопределении компилятор сгенерирует ошибку.

@Override int overriddenMethod()

Подавляет генерируемые компилятором предупреждения.

Предупреждения делятся на непроверенные (unchecked) и устаревшие (deprecation). Первые возникают при использовании устаревшего кода, написанного до дженериков, вторые — при использовании кода, помеченного аннотацией @Deprecated.

Можно подавить как одну категорию, так и обе сразу:

Применяется к методу или конструктору и утверждает, что код не выполняет потенциально небезопасных операций с параметрами varargs. При использовании аннотации подавляются unchecked предупреждения, связанные с varargs.

@SafeVarargs // На самом деле не безопасно! static void m(List. stringLists) < Object[] array = stringLists; ListtmpList = Arrays.asList(42); array[0] = tmpList; //Написано неверно, но скомпилируется без предупреждения String s = stringLists[0].get(0); //ClassCastException >

Используется при описании функционального интерфейса. Подчеркивает, что это именно функциональный интерфейс.

@FunctionalInterface public interface Predicate

Аннотации, применимые к другим аннотациям (мета-аннотации)

Располагаются в пакете java.lang.annotation.

Указывает, сколько хранится отмеченная аннотация.

  • RetentionPolicy.SOURCE . Отмеченная аннотация сохраняется только на уровне исходного кода и игнорируется компилятором.
  • RetentionPolicy.CLASS . Сохраняется компилятором во время компиляции, но игнорируется JVM.
  • RetentionPolicy.RUNTIME . Сохраняется JVM для использования во время выполнения программы.
Читайте также:  Table design in html with css

Указывает, что аннотация, должна быть задокументирована в Javadoc (по умолчанию аннотации не документируются).

Определяет права доступа аннотации (к каким элементам ее можно применять). В аннотации @Target указывается одно из следующих значений:

  • ElementType.ANNOTATION_TYPE . Применяется к аннотации
  • ElementType.CONSTRUCTOR . Применяется к конструктору.
  • ElementType.FIELD . Применяется к полю или свойству.
  • ElementType.LOCAL_VARIABLE . Применяется к локальной переменной.
  • ElementType.METHOD . Применяется к методу.
  • ElementType.PARAMETER . Применяется к параметру метода.
  • ElementType.TYPE . Применяется к любому элементу класса.

Аннотация будет наследоваться дочерним классом (по умолчанию аннотации не наследуются). Применима только к описаниям классов.

Указывает, что аннотация повторяющаяся.

Повторяющиеся аннотации

Определение

Аннотации, которые могут применяться к одному и тому же элементу более одного раза.

Пример

Допустим, вам надо написать аннотацию, запускающую метод в заданное время или по определенному расписанию. В примере созданная аннотация @Schedule будет запускать метод каждый последний день месяца и каждую пятницу в 23:00.

@Schedule(dayOfMonth="last") @Schedule(dayOfWeek="Fri", hour="23") public void doPeriodicCleanup()

Создание повторяющейся аннотации

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

Аннотация должна быть помечена @Repeatable, в скобках указан тип контейнера аннотаций.

import java.lang.annotation.Repeatable; @Repeatable(Schedules.class) public @interface Schedule

Контейнер должен содержать массив повторяющихся аннотаций.

public @interface Schedules

Получение повторяющихся аннотаций

Reflection API предоставляет методы для получения аннотаций. При получении повторяющихся аннотаций поведение методов, которые возвращают одну аннотацию (например, AnnotatedElement.getAnnotation(Class) ) не меняется. Если нужно вернуть более одной, то необходимо сначала получить контейнер. Таким образом устаревший код продолжает работать. Также, для получения повторяющихся аннотаций можно использовать методы Java SE 8 (‘AnnotatedElement.getAnnotationsByType(Class)’).

Для получения информации о всех методах, обратитесь к документации класса AnnotatedElement.

Аннотации типов

Определение

Аннотации типов — аннотации, которые применяются вместе с типами. Везде, где вы видите тип, можно использовать эту аннотацию. Например, с оператором new, при приведении, при имплементации и при использовании throws.

Создание аннотации типов

Для создания аннотации типов в @Target указываются следующие значения, либо одно из них:

@Target () public @interface Test

TYPE_PARAMETER , означает, что аннотацию можно применять к переменным типа (например, MyClass ). TYPE_USE , разрешает применение с любыми типами.

Применение

Аннотации типов предназначены для улучшенного анализа программ и более строгой проверки типов. Например, @NonNull String str; . Java SE8 определяет аннотации типов, но не реализует. Вместо этого предлагается использовать сторонние фреймворки, реализующие их (Checker Framework).

Источник

Оцените статью