blob: dc0e256547fff4741a35fe0b222c8f61679f5627 [file] [log] [blame]
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
= Suporte aos Processadores de Anotação no NetBeans IDE, Parte II: Utilizando Processadores Próprios de Anotação Personalizada no IDE
:jbake-type: tutorial
:jbake-tags: tutorials
:jbake-status: published
:icons: font
:syntax: true
:source-highlighter: pygments
:toc: left
:toc-title:
:description: Suporte aos Processadores de Anotação no NetBeans IDE, Parte II: Utilizando Processadores Próprios de Anotação Personalizada no IDE - Apache NetBeans
:keywords: Apache NetBeans, Tutorials, 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 _
* *Utilizando Processadores Próprios de Anotação Personalizada no IDE*
image::../../../images_www/articles/71/netbeans-stamp-71-72-73.png[title="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 link:http://wiki.netbeans.org/FaqApt[+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
|link:https://netbeans.org/downloads/index.html[+NetBeans IDE+] |7.0, 7.1, 7.2, 7.3
|link:http://www.oracle.com/technetwork/java/javase/downloads/index.html[+JDK (Java Development Kit)+] |versão 6 ou 7
|link:http://code.google.com/p/projectlombok/downloads/list[+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.
[start=3]
. Clique com o botão direito do mouse no nó do projeto AnnProcessor na janela Projetos e escolha Propriedades.
[start=4]
. Na categoria Códigos-fonte, confirme se JDK 6 ou JDK 7 está especificado como o formato de código-fonte/binário.
[start=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.
image::images/packages.png[title="A estrutura do projeto para o processador de anotação."]
[start=4]
. Clique com o botão direito do mouse no pacote Java ``ann`` e selecione Nova > Classe Java.
[start=5]
. Digite * ``Handleable`` * para o nome da classe. Clique em Finalizar.
[start=6]
. Modifique o novo arquivo ``Handleable.java`` para fazer as alterações a seguir. Salve o arquivo.
[source,java]
----
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`` .
[start=7]
. Clique com o botão direito do mouse no pacote * ``proc`` * e selecione Nova > Classe Java.
[start=8]
. Digite * ``HandleableProcessor`` * para o Nome da Classe. Clique em Finalizar.
[start=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)`` .
[source,java]
----
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:
[source,java]
----
@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.
[source,java]
----
public class HandleableProcessor extends AbstractProcessor {
...
}
----
Você agora precisa fornecer um construtor público para a classe.
[source,java]
----
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.
[source,java]
----
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).
[source,java]
----
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.
[source,java]
----
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);
}
*}
----
[start=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.
image::images/demo-project-wizard.png[title="Criando projeto de Demonstração no assistente de Novo Projeto."]
[start=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.
[start=5]
. Modifique a classe ``Main.java`` para adicionar o código a seguir. Salve as alterações.
[source,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");
}*
}
----
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.
[start=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.
[start=7]
. Na guia Compilar, clique em Adicionar Projeto e localize o projeto ``AnnProcessor`` .
image::images/demo-properties-compile.png[title="Guia Compilar na categoria Bibliotecas da janela Propriedades do projeto"]
A guia Compilar corresponde a opção ``-classpath`` do link:http://download.oracle.com/javase/6/docs/technotes/tools/windows/javac.html#options[+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.
[start=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.
[start=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.
image::images/demo-processor-fqn.png[title="Caixa de diálogo FQN do Processador de Anotação"]
A categoria Compilação na janela Propriedades do Projeto deve ser semelhante à imagem a seguir.
image::images/demo-properties-compiling.png[title="Categoria compilação na janela Propriedades do projeto"]
[start=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`` .
[start=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`` .
image::images/demo-generated-sources.png[title="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.
[source,java]
----
package demo;
public abstract class MainExtras {
protected MainExtras() {}
/** Handle something. */
protected final void handleStuff(java.lang.String value) {
System.out.println(value);
}
}
----
[start=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.
image::images/demo-run.png[title="Janela Projetos com Origens Geradas"]
link:/about/contact_form.html?to=3&subject=Feedback:%20Using%20the%20Annotation%20Processors%20Support%20in%20NetBeans%20IDE[+Enviar Feedback neste Tutorial+]
== Consulte Também
Consulte os seguintes recursos para obter mais informações sobre anotações em aplicações Java:
* Documentação Java SE - link:http://download.oracle.com/javase/6/docs/technotes/guides/language/annotations.html[+Anotações+]
* Tutorial Java SE - link:http://download.oracle.com/javase/tutorial/java/javaOO/annotations.html[+Anotações+]
* link:http://download.oracle.com/javase/6/docs/technotes/tools/windows/javac.html#processing[+Compilador do Java: Opções de Processamento de Anotação+]
* link:http://blogs.oracle.com/darcy/[+Weblog de Joseph D. Darcy's Weblog+] - dicas úteis sobre a especificação JSR-269