Java annotation value type

Аннотации в Java, часть I

Это первая часть статьи, посвященной такому языковому механизму Java 5+ как аннотации. Она имеет вводный характер и рассчитана на Junior разработчиков или тех, кто только приступает к изучению языка.

Я занимаюсь онлайн обучением Java и опубликую часть учебных материалов в рамках переработки курса Java Core.

Также я веду курс «Scala for Java Developers» на платформе для онлайн-образования udemy.com (аналог Coursera/EdX).

  1. строю усложняющуюся последовательность примеров
  2. объясняю возможные варианты применения
  3. объясняю логику двигавшую авторами (по мере возможности)
  4. даю большое количество тестов (50-100) всесторонне проверяющее понимание и демонстрирующих различные комбинации
  5. даю лабораторные для самостоятельной работы

Поехали!

Учебный пример: снабдить классы пользователя мета-информацией о «версии класса».

Итерация #1:
Просто ставим @ перед interface.

Итерация #2:
У аннотаций могут быть атрибуты.

@Version(version = 42) public class MyClass <> 

Аннотация выше полностью эквивалентна следующей (без public). В этом аннотации схожи с интерфейсам: отсутствие модификатора области видимости автоматически означает public (а не package private как у классов).

public @interface Version < protected int version(); >>> COMPILATION ERROR: Modifier 'protected' not allowed here 

Далее я буду использовать вариант без модификатора public

Итерация #3:
Если объявить атрибут с именем value, то его можно опускать при использовании

@Version(42) public class MyClass <> 
@Version(value = 42) public class MyClass <> 

Итерация #4:
Для атрибута можно объявить значения по умолчанию

@Version(42) public class MyClass <> 
@Version(value = 42, author = "Jim Smith") public class MyClass
@Version(42, author = "Jim Smith") public class MyClass <> >> COMPILATION ERROR: Annotation attribute must be of the form 'name=value' 

Итерация #5:
Атрибуты могут иметь тип массива

@Author() public class MyClass <> 
public @interface Author2D < String[][] value() default <>; > >> COMPILATION ERROR: Invalid type of annotation member 

Итерация #6:
Возможен забавный трюк: аннотация — атрибут аннотации

@History(< @Version(1), @Version(value = 2, author = "Jim Smith") >) public class MyClass <> 

У аннотаций много ограничений. Перечислим некоторые из них.

Ограничение: тип атрибута

  • примитивы
  • String
  • Class или «any parameterized invocation of Class»
  • enum
  • annotation
  • массив элементов любого из вышеперечисленных типов

Ну что же, давайте действовать в рамках ограничений

Итерация #7:
В качестве типа атрибута нельзя использовать «обычные» классы Java (за исключением java.lang.String и java.lang.Class), скажем java.util.Date

import java.util.Date; public @interface Version < Date date(); >>> COMPILATION ERROR: Invalid type for annotation member 
@Date(year = 2001, month = 1, day = 1) public class MyClass <> 

Итерация #8:
Атрибутом аннотации может быть enum. Из приятного, его можно объявить в объявлении аннотации (как и в объявлении интерфейса тут может быть объявление enum, class, interface, annotation)

public @interface Colored < public enum Color Color value(); > 
import static net.golovach.Colored.Color.RED; @Colored(RED) public class MyClass <> 

Итерация #9:
Атрибутом аннотации может быть классовый литерал.
Аннотация версии включает ссылку на предыдущую версию класса.

public @interface Version < int value(); Classprevious() default Void.class; > 
@Version(1) public class ClassVer1 <> 
@Version(value = 2, previous = ClassVer1.class) public class ClassVer2 <> 

// Да, я знаю, что нормальные люди не включают версию класса в имя класса. Но знаете как нудно придумывать примеры согласованные с реальной практикой?

Итерация #10:
Менее тривиальный пример с классовым литералом, где я не удержался и добавил generic-ов.
Интерфейс «сериализатора» — того, кто может записать экземпляр T в байтовый поток вывода

import java.io.IOException; import java.io.OutputStream; public interface Serializer

import java.io.IOException; import java.io.OutputStream; public class MySerializer implements Serializer  < @Override public void toStream(MyClass obj, OutputStream out) throws IOException < throw new UnsupportedOperationException(); >> 
public @interface SerializedBy < Classvalue(); > 
@SerializedBy(MySerializer.class) public class MyClass <> 

Итерация #11:
Сложный пример

public @interface Version < int version(); Date date(); Author[] authors() default <>; Class previous() default Void.class; > 
import static net.golovach.JobTitle.*; @History(< @Version( version = 1, date = @Date(year = 2001, month = 1, day = 1)), @Version( version = 2, date = @Date(year = 2002, month = 2, day = 2), authors = <@Author(value = "Jim Smith", title = JUNIOR)>, previous = MyClassVer1.class), @Version( version = 3, date = @Date(year = 2003, month = 3, day = 3), authors = < @Author(value = "Jim Smith", title = MIDDLE), @Author(value = "Anna Lea")>, previous = MyClassVer2.class) >) public class MyClassVer3 <> 

Ограничение: значения атрибутов — константы времени компиляции/загрузки JVM

Должна быть возможность вычислить значения атрибутов аннотаций в момент компиляции или загрузки класса в JVM.

public @interface SomeAnnotation
@SomeAnnotation( count = 1 + 2, name = MyClass.STR + "Hello" ) public class MyClass
@SomeAnnotation( count = (int) Math.PI, name = "" + Math.PI ) public class MyClass <> 
@SomeAnnotation( count = (int) Math.sin(1), name = "Hello!".toUpperCase() ) public class MyClass <> >> COMPILATION ERROR: Attribute value must be constant 

Заключение

  • Аннотации, модифицирующие поведение других аннотаций: @ Target, @ Retention, @ Documented, @ Inherited
  • Аннотации, модифицирующие поведение компилятора и JVM: @ Deprecated, @ Override, @ SafeVarargs, @ SuppressWarnings
  • Чтение аннотаций с помощью Reflection API

Контакты

Я занимаюсь онлайн обучением Java (вот курсы программирования) и публикую часть учебных материалов в рамках переработки курса Java Core. Видеозаписи лекций в аудитории Вы можете увидеть на youtube-канале, возможно, видео канала лучше систематизировано в этой статье.

skype: GolovachCourses
email: GolovachCourses@gmail.com

Источник

Аннотации в 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 , а его элементы похожи на методы, которые могут иметь дефолтные значения.

Пример

Допустим, в какой-то 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 для использования во время выполнения программы.

Указывает, что аннотация, должна быть задокументирована в 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).

Источник

Читайте также:  Php mysqli prepare select
Оцените статью