Suporte aos Processadores de Anotação no NetBeans IDE, Parte II: Utilizando Processadores Próprios de Anotação Personalizada no IDE

Contribuição de Jesse Glick, redigido e mantido por Irina Filippova

O conteúdo desta página se aplica ao NetBeans IDE 7.0, 7.1, 7.2 e 7.3

Nesta seção do tutorial, você aprenderá a adicionar um processador de anotação personalizado de redação própria a um projeto no IDE. Este tutorial não ensina como criar um processador de anotação. Ele explica como adicioná-lo a um projeto NetBeans IDE.

A aplicação de amostra usada nesta seção foi criada por Jesse Glick e publicada como uma entrada de FAQ das releases anteriores do IDE.

O processador de anotação usado como exemplo gera uma classe principal da classe anotada. A classe principal gerada também contém um método chamado usando a classe anotada. Siga as instruções abaixo sobre como criar e adicionar um processador personalizado de anotação em um projeto do IDE.

Para concluir este tutorial, você precisa dos seguintes recursos e softwares.

Software ou Recurso Versão Necessária
NetBeans IDE 7.0, 7.1, 7.2, 7.3
JDK (Java Development Kit) versão 6 ou 7
lombok.jar v1.12.4 ou mais recente

Definindo uma Anotação e Criando um Processador de Anotação

Neste exercício, você criará um projeto de biblioteca de classes.

  1. Escolha Arquivo > Novo Projeto e selecione o tipo de projeto de Bibliotecas de Classes Java na categoria Java. Clique em Próximo.
  2. Digite AnnProcessor como Nome do Projeto e especifique um local para o projeto. Clique em Finalizar.

    Quando você clica em Finalizar, o IDE cria o projeto de biblioteca de classes e lista o projeto na janela Projetos.

  3. Clique com o botão direito do mouse no nó do projeto AnnProcessor na janela Projetos e escolha Propriedades.
  4. Na categoria Códigos-fonte, confirme se JDK 6 ou JDK 7 está especificado como o formato de código-fonte/binário.
  5. Selecione a guia Bibliotecas e confirme se a plataforma Java está definida como JDK 1.6 ou JDK 1.7. Clique em OK para fechar a janela Propriedades do Projeto.

Neste exercício, você criará dois pacotes Java e uma classe Java em cada um destes pacotes.

  1. Clique com o botão direito do mouse no nó Pacotes de Código-fonte sob o nó do projeto AnnProcessor e escolha Novo > Pacote Java.
  2. Digite ann como Nome do Pacote e clique em Finalizar para criar o novo pacote Java.
  3. Repita as duas etapas anteriores para criar um pacote Java chamado proc.

    Após ter criado os dois pacotes Java, a estrutura do projeto deverá ser similar à seguinte imagem.

    tela da janela Projetos mostrando pacotes Java
  4. Clique com o botão direito do mouse no pacote Java ann e selecione Nova > Classe Java.
  5. Digite Handleable para o nome da classe. Clique em Finalizar.
  6. Modifique o novo arquivo Handleable.java para fazer as alterações a seguir. Salve o arquivo.
    package ann;
    
    public @interface Handleable {
    
    }

    É assim que as anotações são declaradas, de forma muito similar a uma declaração de interface. A diferença é que a palavra-chave interface precisa ser precedida por um sinal at (@). Essa anotação é denominada Handleable.

    Informações Adicionais. Nas declarações de anotação, você também pode especificar parâmetros adicionais, por exemplo, quais tipos de elementos podem ser anotados, por exemplo, classes ou métodos. Você fazer isso adicionando @Target(value = {ElementType.TYPE}) para classes e @Target(value = {ElementType.METHOD}). Isso, a declaração de anotação torna-se anotada com meta-anotações.

    Agora precisamos adicionar um código para que o processador de anotação processe a anotação Handleable.

  7. Clique com o botão direito do mouse no pacote proc e selecione Nova > Classe Java.
  8. Digite HandleableProcessor para o Nome da Classe. Clique em Finalizar.
  9. Modifique a classe HandleableProcessor.java para adicionar o código a seguir. Salve as alterações.

    Observação. O valor de @SupportedSourceVersion (em negrito) dependerá da versão do JDK que você está usando e será (SourceVersion.RELEASE_7) ou (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);
        }
    }

    Vamos examinar mais de perto as partes principais que compõem o código para o processador de anotações (observe que, por conveniência, somente partes do código são fornecidas).

    Primeiro, você especifica os tipos de anotações que o processador de anotações suporta (usando @SupportedAnnotationTypes) e a versão dos arquivos de código-fonte que são suportados (usando @SupportedSourceVersion); nesse caso, a versão é JDK 6:

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

    A seguir, declare uma classe pública para o processador que estenda a classe AbstractProcessor do pacote javax.annotation.processing. AbstractProcessor é a superclasse padrão para processadores de anotação concretos, que contém os métodos necessários para processar anotações.

    public class HandleableProcessor extends AbstractProcessor {
    ...
    }

    Você agora precisa fornecer um construtor público para a classe.

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

    A seguir, chame o método de process() da classe AbstractProcessor principal. Por meio deste método, as anotações disponíveis para processamento são fornecidas. Além disso, este método contém informações sobre o ciclo de processamento.

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

    A lógica do processador de anotação está contida dentro do método process() da classe AbstractProcessor. Observe que, por meio de AbstractProcessor, você também acessa a interface ProcessingEnvironment, que permite que os processadores de anotação usem diversos recursos úteis, como um Filer (um handler de arquivamento que permite que os processadores de anotação criem novos arquivos) e um Messager (um meio pelo qual os processadores de anotação reportam erros).

    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; } ... }

    O último bloco neste código declara o método capitalize que é usado para colocar em maiúscula o nome do elemento anotado.

    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. Compile o projeto clicando com o botão direito do mouse no projeto AnnProcessor e escolhendo Compilar.

Usando o processador de anotação no IDE

Nesta seção, você criará um projeto da Aplicação Java no qual o processador de anotações será usado.

  1. Escolha Arquivo > Novo Projeto e selecione o tipo de projeto da Aplicação Java na categoria Java. Clique em Próximo.
  2. Na página Nome e Localização, digite Demo como Nome do Projeto e especifique o local do projeto.
  3. Digite demo.Main no campo Criar Classe Principal. Clique em Finalizar.
    tela do assistente Novo Projeto
  4. Abra a janela Propriedades do Projeto e confirme se JDK 6 ou JDK 7 está selecionado como o formato de código-fonte/binário no painel Códigos-fonte e se a plataforma Java está definida como JDK 1.6 ou JDK 1.7 no painel Bibliotecas.
  5. Modifique a classe Main.java para adicionar o código a seguir. Salve as alterações.
    package demo;
    
    import ann.Handleable;
    
    public class Main extends MainExtras {
    
        @Handleable
        private String stuff;
    
        public static void main(String[] args) {
            new Main().handleStuff("hello");
        }
    }

    O código contém os seguintes elementos:

    • instrução de importação para o processador personalizado de anotação ann.Handleable
    • a classe pública Main que estende a classe MainExtras (MainExtras deve ser gerada por seu processador de anotação durante a compilação)
    • um campo privado denominado stuff que é anotado com a anotação @Handleable
    • o método main que chama o método handleStuff, declarado na classe MainExtras automaticamente gerada

      Em nosso exemplo simples, o método handleStuff somente imprime o valor atual. Você pode modificar este método para executar outras tarefas.

    Após salvar o código Main.java, você verá que o IDE relata diversos erros de compilação. Isso acontece porque o processador de anotação ainda não foi adicionado no projeto.

  6. Clique com o botão direito do mouse no nó do projeto Demo, na janela Projetos, escolha Propriedades e, em seguida, selecione a categoria Bibliotecas na janela Propriedades do Projeto.
  7. Na guia Compilar, clique em Adicionar Projeto e localize o projeto AnnProcessor.
    tela da guia Compilar na categoria Bibliotecas da janela Propriedades do projeto

    A guia Compilar corresponde a opção -classpath do compilador Java. Como o processador de anotação é um arquivo JAR único que contém a definição da anotação e o processador de anotação, ele deve ser adicionado na classpath do projeto, que é a guia Compilar.

  8. Selecione a categoria Compilação na janela Propriedades do Projeto e marque as caixas de seleção Ativar Processamento de Anotações e Ativar Processamento de Anotações no Editor.
  9. Especifique o processador de anotações a ser executado clicando no botão Adicionar ao lado da área de texto Processadores de Anotações e digitando proc.HandleableProcessor no campo FQN do Processador de Anotações.
    tela da caixa de diálogo FQN do Processador de Anotações

    A categoria Compilação na janela Propriedades do Projeto deve ser semelhante à imagem a seguir.

    tela da categoria Compilação na janela Propriedades do projeto
  10. Clique em OK na janela Propriedades.

    Observação. No arquivo Main.java talvez você ainda veja os erros de compilação. Isso é porque o IDE ainda não pode localizar o arquivo MainExtras.java que declara o método handleStuff. O arquivo MainExtras.java será gerado após você desenvolver o projeto Demo pela primeira vez. Se Compilar ao Salvar estiver ativado para seu projeto, o IDE compilou o projeto quando você salvou o Main.java.

  11. Clique com o botão direito do mouse no projeto Demo e escolha Construir.

    Após construir o projeto, se você examinar os projetos na janela Projetos, poderá agora ver um novo nó Códigos-fonte Gerados com o arquivo demo/MainExtras.java.

    tela da janela Projetos com Origens Geradas

    Caso você revise o conteúdo do arquivo MainExtras.java gerado, verá que o processador de anotações gerou a classe MainExtras com o método handleStuff. O método handleStuff é aquele chamado a partir do arquivo Main.java anotado.

    package demo;
    public abstract class MainExtras {
        protected MainExtras() {}
        /** Handle something. */
        protected final void handleStuff(java.lang.String value) {
            System.out.println(value);
        }
    }
  12. Clique com o botão direito do mouse no projeto Demonstração e escolha Executar.

    Quando você clicar em Executar, deverá ver o seguinte na janela Saída. O projeto Demonstração é compilado e imprime a mensagem.

    tela da janela Projetos com Origens Geradas

Consulte Também

Consulte os seguintes recursos para obter mais informações sobre anotações em aplicações 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