Spec-Zone .ru
спецификации, руководства, описания, API
Содержание документации

Аннотации

Много API требуют изрядного количества шаблонного кода. Например, чтобы записать веб-сервис JAX-RPC, следует обеспечить парный интерфейс и реализацию. Этот шаблон мог быть сгенерирован автоматически инструментом, если бы программа была "украшена" аннотациями, указывающими, какие методы были удаленно доступны.

Другие API требуют, ", чтобы файлы стороны” сохранялись параллельно с программами. Например JavaBeans требует a BeanInfo класс, который будет сохраняться параллельно с бобом, и Предприятием JavaBeans (EJB), требует дескриптора развертывания. Это было бы более удобным и менее подверженным ошибкам, если бы информация в этих файлах стороны сохранялась как аннотации в программе непосредственно.

У платформы Java всегда были различные оперативные механизмы аннотации. Например transient модификатор является оперативной аннотацией, указывающей, что поле должно быть проигнорировано подсистемой сериализации, и @deprecated тег javadoc является оперативной аннотацией, указывающей, что метод больше не должен использоваться. С выпуска 5.0 у платформы есть аннотация общего назначения (также известный как метаданные) средство, которое разрешает Вам определять и использовать свои собственные типы аннотации. Средство состоит из синтаксиса для того, чтобы объявить типы аннотации, синтаксис для того, чтобы аннотировать объявления, API для того, чтобы считать аннотации, представление файла класса для аннотаций, и инструмент обработки аннотации.

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

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

Типичные прикладные программисты никогда не должны будут определять тип аннотации, но не трудно сделать так. Описания типа аннотации подобны нормальным интерфейсным объявлениям. Знак at-sign (@) предшествует interface ключевое слово. Каждое объявление метода определяет элемент типа аннотации. У объявлений метода не должно быть никаких параметров или a throws пункт. Возвратитесь типы ограничиваются примитивам, String, Class, перечисления, аннотации, и массивы предыдущих типов. У методов могут быть значения по умолчанию. Вот описание типа аннотации в качестве примера:

/**
 * Describes the Request-For-Enhancement(RFE) that led
 * to the presence of the annotated API element.
 */
public @interface RequestForEnhancement {
    int    id();
    String synopsis();
    String engineer() default "[unassigned]"; 
    String date()    default "[unimplemented]"; 
}

Как только тип аннотации определяется, можно использовать его, чтобы аннотировать объявления. Аннотация является специальным видом модификатора, и может использоваться где угодно что другие модификаторы (такой как public, static, или final) может использоваться. Условно, аннотации предшествуют другим модификаторам. Аннотации состоят из знака at-sign (@) сопровождаемый типом аннотации и заключенным в скобки списком пар значения элемента. Значения должны быть константами времени компиляции. Вот объявление метода с аннотацией, соответствующей типу аннотации, объявленному выше:

@RequestForEnhancement(
    id       = 2868724,
    synopsis = "Enable time-travel",
    engineer = "Mr. Peabody",
    date     = "4/1/3007"
)
public static void travelThroughTime(Date destination) { ... }

Тип аннотации без элементов называют типом аннотации маркера, например:

/**
 * Indicates that the specification of the annotated API element
 * is preliminary and subject to change.
 */
public @interface Preliminary { }

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

@Preliminary public class TimeTravel { ... }

В аннотациях с единственным элементом нужно назвать элемент value, как показано ниже:

/**
 * Associates a copyright notice with the annotated API element.
 */
public @interface Copyright {
    String value();
}

Это допустимо опустить имя элемента и равняется знаку (=) в одноэлементной аннотации, имя элемента которой value, как показано ниже:

@Copyright("2002 Yoyodyne Propulsion Systems")
public class OscillationOverthruster { ... }

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

import java.lang.annotation.*;

/**
 * Indicates that the annotated method is a test method.
 * This annotation should be used only on parameterless static methods.
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Test { }

Отметьте, что описание типа аннотации самостоятельно аннотируется. Такие аннотации вызывают метааннотациями. Первое (@Retention(RetentionPolicy.RUNTIME)) указывает, что аннотации с этим типом должны быть сохранены VM, таким образом, они могут быть считаны отражающим образом во время выполнения. Второе (@Target(ElementType.METHOD)) указывает, что этот тип аннотации может использоваться, чтобы аннотировать только объявления метода.

Вот пример программы, некоторые из чей методов аннотируются вышеупомянутым интерфейсом:

public class Foo {
    @Test public static void m1() { }
    public static void m2() { }
    @Test public static void m3() {
        throw new RuntimeException("Boom");
    }
    public static void m4() { }
    @Test public static void m5() { }
    public static void m6() { }
    @Test public static void m7() {
        throw new RuntimeException("Crash");
    }
    public static void m8() { }
}

Вот инструмент тестирования:

import java.lang.reflect.*;

public class RunTests {
   public static void main(String[] args) throws Exception {
      int passed = 0, failed = 0;
      for (Method m : Class.forName(args[0]).getMethods()) {
         if (m.isAnnotationPresent(Test.class)) {
            try {
               m.invoke(null);
               passed++;
            } catch (Throwable ex) {
               System.out.printf("Test %s failed: %s %n", m, ex.getCause());
               failed++;
            }
         }
      }
      System.out.printf("Passed: %d, Failed %d%n", passed, failed);
   }
}

Инструмент берет имя класса в качестве параметра командной строки и выполняет итерации по всем методам именованного класса, пытающегося вызвать каждый метод, который аннотируется Test тип аннотации (определенный выше). Отражающий запрос, чтобы узнать, есть ли у метода a Test аннотация выделяется в зеленом. Если вызов метода испытаний выдает исключение, тест, как считают, перестал работать, и отчет отказа печатается. Наконец, сводка печатается, показывая число тестов, которые передали и перестали работать. Вот то, как это смотрит, когда Вы работаете на инструменте тестирования Foo программа (выше):

$ java RunTests Foo
Test public static void Foo.m3() failed: java.lang.RuntimeException: Boom 
Test public static void Foo.m7() failed: java.lang.RuntimeException: Crash 
Passed: 2, Failed 2
В то время как этот инструмент тестирования является ясно игрушкой, он демонстрирует питание аннотаций и мог легко быть расширен, чтобы преодолеть его ограничения.

Oracle и/или его филиалы Авторское право © 1993, 2011, Oracle и/или его филиалы. Все права защищены.
Свяжитесь с Нами