Поддержка обработчиков аннотаций в IDE NetBeans (часть II) Использование пользовательских обработчиков аннотаций в IDE

Составитель:, автор и редактор: Ирина Филиппова (Irina Filippova)

Содержимое на этой странице применимо к IDE NetBeans 7.0, 7.1, 7.2 и 7.3

В этом разделе учебного курса описываются способы добавления собственного обработчика особых аннотаций в проект в среде IDE. Написание обработчика не входит в круг задач данного учебного курса. Здесь описывается добавление его к проекту IDE NetBeans.

Образец приложения, используемый в этом приложении, был создан Джесси Глик (Jesse Glick) и опубликован как Часто задаваемые вопросы по вводу для предыдущих выпусков IDE.

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

Для работы с этим учебным курсом требуются программное обеспечение и ресурсы, перечисленные ниже.

Программное обеспечение или материал Требуемая версия
IDE NetBeans 7.0, 7.1, 7.2, 7.3
Комплект для разработчика на языке Java (JDK) версия 6 или 7
lombok.jar версия 1.12.4 и более поздние

Определение аннотации и создание обработчика аннотаций

В этом упражнении мы создадим проект библиотеки классов.

  1. Выберите File ("Файл") > New Project ("Создать проект") и выберите тип проекта Java Class Library ("Библиотека классов Java") в категории Java. Нажмите кнопку "Далее".
  2. Введите AnnProcessor в поле "Имя проекта" и укажите местоположение для проекта. Нажмите кнопку "Завершить".

    При нажатии кнопки "Готово" среда IDE создаст проект библиотеки классов, который появится в окне Projects ("Проекты").

  3. Щелкните правой кнопкой мыши узел проекта AnnProcessor в окне Projects ("Проекты") и выберите Properties ("Свойства").
  4. В категории "Источники" подтвердите, что для JDK 6 или JDK 7 указан формат исходного кода/двоичный формат.
  5. Выберите вкладку "Библиотеки" и подтвердите, что платформой Java является JDK 1.6 или JDK 1.7. Нажмите кнопку "ОК", чтобы закрыть окно Project Properties ("Свойства проекта").

В этом упражнении мы создадим несколько пакетов Java и по одному классу Java в каждом из пакетов.

  1. В проекте 'AnnProcessor' щелкните правой кнопкой мыши узел 'Пакеты исходных кодов' и выберите 'Создать > Пакет Java'.
  2. Введите ann в поле "Имя пакета" и нажмите кнопку "Готово" для создания нового пакета Java.
  3. Повторите два предыдущих действия, чтобы создать пакет Java под названием proc.

    После создания двух пакетов Java структура проекта должна быть подобной изображенной ниже.

    снимок окна 'Проекты', в котором отображаются пакеты Java
  4. Щелкните правой кнопкой мыши пакет Java ann и выберите New ("Создать") > Java class ("Класс Java").
  5. Введите Handleable в поле Class Name ("Имя класса"). Нажмите кнопку "Завершить".
  6. Измените файл Handleable.java, добавив приведенный ниже код. Сохраните файл.
    package ann;
    
    public @interface Handleable {
    
    }

    Так объявляются аннотации -- совершенно аналогично объявлению интерфейса. Различием является то, что ключевому слову interface должен предшествовать знак @. Эта аннотация именуется Handleable (обрабатываемой).

    Дополнительные сведения. В объявлениях аннотаций можно указать дополнительные параметры, например, типы элементов, к которым можно добавить аннотации, например, классы или методы. Для этого добавляется @Target(value = {ElementType.TYPE}) для классов и @Target(value = {ElementType.METHOD}). Таким образом, объявление аннотаций становится автоматическим с помощью мета-аннотаций.

    Теперь необходимо добавить к обработчику аннотаций код для обработки аннотации Handleable.

  7. Щелкните правой кнопкой мыши пакет Java proc и выберите New ("Создать") > Java class ("Класс Java").
  8. Введите HandleableProcessor в поле Class Name ("Имя класса"). Нажмите кнопку "Завершить".
  9. Измените класс HandleableProcessor.java, добавив нижеприведенный код. Сохраните изменения.

    Примечание. Значение @SupportedSourceVersion (выделено жирным шрифтом) зависит от используемой версии JDK и может быть двух вариантов: (SourceVersion.RELEASE_7) или (SourceVersion.RELEASE_6).

    package proc;
    
    import ann.Handleable;
    import java.io.IOException;
    import java.io.PrintWriter;
    import java.io.Writer;
    import java.util.Set;
    import javax.annotation.processing.AbstractProcessor;
    import javax.annotation.processing.RoundEnvironment;
    import javax.annotation.processing.SupportedAnnotationTypes;
    import javax.annotation.processing.SupportedSourceVersion;
    import javax.lang.model.SourceVersion;
    import javax.lang.model.element.Element;
    import javax.lang.model.element.ElementKind;
    import javax.lang.model.element.TypeElement;
    import javax.lang.model.type.TypeMirror;
    import javax.tools.Diagnostic;
    import javax.tools.JavaFileObject;
    
    @SupportedAnnotationTypes("ann.Handleable")
    @SupportedSourceVersion(SourceVersion.RELEASE_7)
    public class HandleableProcessor extends AbstractProcessor {
    
        /** public for ServiceLoader */
        public HandleableProcessor() {
        }
    
        public boolean process(Set<? extends TypeElement> annotations,
                RoundEnvironment roundEnv) {
            for (Element e : roundEnv.getElementsAnnotatedWith(Handleable.class)) {
                if (e.getKind() != ElementKind.FIELD) {
                    processingEnv.getMessager().printMessage(
                            Diagnostic.Kind.WARNING,
                            "Not a field", e);
                    continue;
                }
                String name = capitalize(e.getSimpleName().toString());
                TypeElement clazz = (TypeElement) e.getEnclosingElement();
                try {
                    JavaFileObject f = processingEnv.getFiler().
                            createSourceFile(clazz.getQualifiedName() + "Extras");
                    processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE,
                            "Creating " + f.toUri());
                    Writer w = f.openWriter();
                    try {
                        PrintWriter pw = new PrintWriter(w);
                        pw.println("package "
                                + clazz.getEnclosingElement().getSimpleName() + ";");
                        pw.println("public abstract class "
                                + clazz.getSimpleName() + "Extras {");
                        pw.println("    protected " + clazz.getSimpleName()
                                + "Extras() {}");
                        TypeMirror type = e.asType();
                        pw.println("    /** Handle something. */");
                        pw.println("    protected final void handle" + name
                                + "(" + type + " value) {");
                        pw.println("        System.out.println(value);");
                        pw.println("    }");
                        pw.println("}");
                        pw.flush();
                    } finally {
                        w.close();
                    }
                } catch (IOException x) {
                    processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
                            x.toString());
                }
            }
            return true;
        }
    
        private static String capitalize(String name) {
            char[] c = name.toCharArray();
            c[0] = Character.toUpperCase(c[0]);
            return new String(c);
        }
    }

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

    Сперва следует указать типы аннотаций, поддерживаемые обработчиком аннотаций (используя @SupportedAnnotationTypes) и поддерживаемую версию исходных файлов (используя @SupportedSourceVersion). В данном случае версией является JDK 6:

    @SupportedAnnotationTypes("ann.Handleable")
    @SupportedSourceVersion(SourceVersion.RELEASE_6)

    Затем следует объявить общедоступный класс для обработчика, расширяющий классAbstractProcessor из пакета javax.annotation.processing. AbstractProcessor является стандартным надклассом для обработчиков конкретных аннотаций и содержит необходимые методы для обработки аннотаций.

    public class HandleableProcessor extends AbstractProcessor {
    ...
    }

    Теперь необходимо предоставить общедоступный конструктор для данного класса.

    public class HandleableProcessor extends AbstractProcessor {
        public HandleableProcessor() {
        }
    ...
    
    }

    Затем следует вызвать метод process() родительского класса AbstractProcessor. Посредством этого метода предоставляются аннотации, доступные для обработки. Кроме того, этот метод содержит данные о цикле обработки.

    public class HandleableProcessor extends AbstractProcessor {
       ...
         public boolean process(Set<? extends TypeElement> annotations,
                RoundEnvironment roundEnv) {
         ...
         }
    
    }

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

    public class HandleableProcessor extends AbstractProcessor {
       ...
         public boolean process(Set<? extends TypeElement> annotations,
                RoundEnvironment roundEnv) {
    //For each element annotated with the Handleable annotation for (Element e : roundEnv.getElementsAnnotatedWith(Handleable.class)) {
    //Check if the type of the annotated element is not a field. If yes, return a warning.
    if (e.getKind() != ElementKind.FIELD) {
    processingEnv.getMessager().printMessage(
    Diagnostic.Kind.WARNING,
    "Not a field", e);
    continue;
    }
    //Define the following variables: name and clazz.
    String name = capitalize(e.getSimpleName().toString());
    TypeElement clazz = (TypeElement) e.getEnclosingElement();
    //Generate a source file with a specified class name. try {
    JavaFileObject f = processingEnv.getFiler().
    createSourceFile(clazz.getQualifiedName() + "Extras");
    processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE,
    "Creating " + f.toUri());
    Writer w = f.openWriter();
    //Add the content to the newly generated file. try {
    PrintWriter pw = new PrintWriter(w);
    pw.println("package "
    + clazz.getEnclosingElement().getSimpleName() + ";");
    pw.println("public abstract class "
    + clazz.getSimpleName() + "Extras {");
    pw.println(" protected " + clazz.getSimpleName()
    + "Extras() {}");
    TypeMirror type = e.asType();
    pw.println(" /** Handle something. */");
    pw.println(" protected final void handle" + name
    + "(" + type + " value) {");
    pw.println(" System.out.println(value);");
    pw.println(" }");
    pw.println("}");
    pw.flush();
    } finally {
    w.close();
    }
    } catch (IOException x) {
    processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
    x.toString());
    }
    }

    return true; } ... }

    В последнем блоке этого кода объявляется метод capitalize, используемый для написания имени аннотированного элемента с заглавной буквы.

    public class HandleableProcessor extends AbstractProcessor {
       ...
    
      private static String capitalize(String name) {
    char[] c = name.toCharArray();
    c[0] = Character.toUpperCase(c[0]);
    return new String(c);
    }
    }
  10. Создайте проект, щелкнув правой кнопкой мыши проект AnnProcessor и выбрав 'Сборка'.

Работа с обработчиком аннотаций в среде IDE

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

  1. Выберите File ("Файл") > New Project ("Создать проект") и выберите тип проекта Java Application ("Приложение Java") в категории Java. Нажмите кнопку "Далее".
  2. На странице "Имя и расположение" введите Demo в поле "Имя проекта" и укажите расположение проекта.
  3. Введите demo.Main в поле Create Main Class ("Создать главный класс"). Нажмите кнопку "Завершить".
    моментальный снимок мастера создания проектов
  4. Откройте окно 'Свойства проекта' и убедитесь, что JDK 6 или JDK 7 выбран как двоичный формат/формат исходного кода на панели "Исходные коды", а также что JDK 1.6 or JDK 1.7 установлен как платформа Java на панели "Библиотеки".
  5. Измените класс Main.java, добавив приведенный ниже код. Сохраните изменения.
    package demo;
    
    import ann.Handleable;
    
    public class Main extends MainExtras {
    
        @Handleable
        private String stuff;
    
        public static void main(String[] args) {
            new Main().handleStuff("hello");
        }
    }

    Данный код содержит следующие элементы:

    • оператор импорта для обработчика особых аннотаций ann.Handleable;
    • общедоступный класс Main, расширяющий класс MainExtras (MainExtras должен быть создан обработчиком аннотаций во время компиляции);
    • закрытое поле под названием stuff, с аннотацией @Handleable;
    • метод main, вызывающий метод handleStuff, который объявляется в автоматически создаваемом классе MainExtras.

      В этом простом примере метод handleStuff только распечатывает текущее значение. Назначение метода можно изменить.

    После сохранения кода Main.java можно увидеть, что среда IDE сообщает о ряде ошибок компиляции. Это происходит, поскольку обработчик аннотаций еще не добавлен в проект.

  6. Щелкните правой кнопкой мыши узел проекта Demo в окне "Проекты", выберите "Свойства", затем выберите категорию "Библиотеки" в окне 'Свойства проекта'.
  7. На вкладке Compile ("Компиляция") щелкните Add Project ("Добавить проект") и найдите проект AnnProcessor.
    снимок вкладки 'Компилировать' в категории 'Библиотеки' окна свойств проекта

    Вкладка "Компиляция" соответствует параметру -classpath компилятора Java. Поскольку обработчик аннотаций является единым файлом JAR, который содержит как определение аннотаций, так и обработчик аннотаций, его следует добавить к пути классов для проекта, которым является вкладка Compile ("Компиляция").

  8. Выберите категорию "Компиляция" в окне "Свойства проекта" и установите флажки "Разрешить обработку аннотаций" и "Разрешить обработку аннотаций в редакторе".
  9. Укажите, какой обработчик аннотаций должен быть запущен, нажав кнопку Add ("Добавить") рядом с текстовой областью обработчиков аннотаций и введя proc.HandleableProcessor в поле FQN ("Полностью определенное имя") обработчика аннотаций.
    снимок диалогового окна 'FQN обработчика аннотаций'

    Категория Compiling ("Компиляция") в окне Project Properties ("Свойства проекта") должна выглядеть, как на приведенном ниже изображении.

    снимок категории &quot;Компиляция&quot; в окне &quot;Свойства проекта&quot;.
  10. Нажмите кнопку OK в окне Properties ("Свойства").

    Примечание. В файле Main.java все еще могут отображаться ошибки компиляции. Это происходит, поскольку в среде IDE еще не определено местоположение файла MainExtras.java, в котором объявляется метод handleStuff. После первого создания проекта Demo будет создан файл MainExtras.java. Если для проекта включено режим Compile On Save ("Компилировать при сохранении"), среда IDE компилирует проект при сохранении Main.java.

  11. Щелкните правой кнопкой мыши проект Demo и выберите Build ("Сборка").

    Если после сборки проекта взглянуть на него в окне Projects ("Проекты"), то можно будет увидеть новый узел Generated Sources с файлом demo/MainExtras.java.

    снимок окна 'Проекты' с созданными источниками

    При просмотре содержимого созданного файла MainExtras.java можно увидеть, что обработчик аннотаций создал класс MainExtras с методом handleStuff. Метод handleStuff и является методом, вызываемым из аннотированного файла Main.java.

    package demo;
    public abstract class MainExtras {
        protected MainExtras() {}
        /** Handle something. */
        protected final void handleStuff(java.lang.String value) {
            System.out.println(value);
        }
    }
  12. Щелкните правой кнопкой мыши проект Demo и выберите Run ("Запустить").

    При щелчке Run ("Запустить") в окне вывода можно будет увидеть следующее. Выполняется компиляция проекта Demo, и на экран выводится сообщение.

    снимок окна 'Проекты' с созданными источниками

Дополнительные сведения

Ознакомьтесь со следующими ресурсами для получения дополнительных сведений об аннотациях в приложениях Java:

get support for the NetBeans

Support


By use of this website, you agree to the NetBeans Policies and Terms of Use. © 2013, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo