<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> | |
<!-- | |
Copyright (c) 2010, 2011 Oracle and/or its affiliates. All rights reserved. | |
--> | |
<html> | |
<head> | |
<title>Annotation Processors Support in the NetBeans IDE</title> | |
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" > | |
<link rel="stylesheet" type="text/css" href="../../../netbeans.css"> | |
<meta name="keywords" content="NETBEANS, TUTORIAL, GUIDE, USER, DOCUMENTATION"> | |
<meta name="description" content="A very simple and quick introduction to the NetBeans IDE workflow by walking you through the creation of a | |
simple Hello World Java console application." > | |
</head> | |
<body> | |
<h1>Annotation Processors Support in the NetBeans IDE, Part II: Using Own Custom Annotation Processors in the IDE </h1> | |
<p><em>Contributed by Jesse Glick, written and maintained by Irina Filippova </em></p> | |
<div class="margin-around"> | |
<div class="feedback-box margin-around float-left" style="margin-right:15px"> | |
<p><b>Contents</b></p> | |
<ul class="toc"> | |
<li><a href="annotations.html">Introduction</a></li> | |
<li><a href="annotations.html#map">Map of javac Options and IDE Commands</a> </li> | |
<li><a href="annotations-lombok.html">Using Project Lombok for Custom Annotations</a></li> | |
<li><strong>Using Own Custom Annotation Processors in the IDE</strong> | |
<ul> | |
<li><a href="#defineann">Defining an Annotation and Creating an Annotation Processor</a></li> | |
<li><a href="#useprocessor">Using the Annotation Processor</a> </li> | |
</ul> | |
</li> | |
<li><a href="#seealso" title="See Also"><strong>See Also </strong></a></li> | |
</ul> | |
</div> | |
</div> | |
<img src="../../../images_www/articles/71/netbeans-stamp-71-72-73.png" class="stamp" alt="Content on this page applies to NetBeans IDE 7.0, 7.1, 7.2 and 7.3" title="Content on this page applies to the NetBeans IDE 7.0, 7.1, 7.2 and 7.3" /> | |
<p>In this section of the tutorial, you will learn how to add a self-written custom annotation processor to a project in the IDE. This tutorial does not teach you how to write an annotation processor. It explains how to add it to a NetBeans IDE project. </p> | |
<p>The sample application used in this section was created by Jesse Glick and published as an <a href="http://wiki.netbeans.org/FaqApt" target="_blank">FAQ entry</a> for the previous IDE releases. </p> | |
<p>The annotation processor used as the example generates a parent class for the annotated class. The generated parent class also contains a method that is called from the annotated class. Follow the instructions below on how to create and add a custom annotation processor to an IDE's project. </p> | |
<p style="clear:both"><b>To complete this tutorial, you need the following software and resources.</b></p> | |
<table> | |
<tbody> | |
<tr> | |
<th class="tblheader" scope="col">Software or Resource</th> | |
<th class="tblheader" scope="col">Version Required</th> | |
</tr> | |
<tr> | |
<td class="tbltd1"><a href="https://netbeans.org/downloads/index.html" target="_blank">NetBeans IDE</a></td> | |
<td class="tbltd1">7.0, 7.1, 7.2, 7.3</td> | |
</tr> | |
<tr> | |
<td class="tbltd1"><a href="http://www.oracle.com/technetwork/java/javase/downloads/index.html">Java Development Kit (JDK)</a></td> | |
<td class="tbltd1">version 6 or 7</td> | |
</tr> | |
</tbody> | |
</table> | |
<h2><a name="defineann"></a>Defining an Annotation and Creating an Annotation Processor</h2> | |
<p>In this exercise you will create a class library project.</p> | |
<ol> | |
<li>Choose File > New Project and select the Java Class Library project type in the Java category. Click Next.</li> | |
<li>Type <strong><tt>AnnProcessor</tt></strong> as the Project Name and specify a location for the project. Click Finish. | |
<p>When you click Finish, the IDE creates the class library project and lists the project in the Projects window.</p> | |
</li> | |
<li>Right-click the AnnProcessor project node in the Projects window and choose Properties.</li> | |
<li>In the Sources category, confirm that either JDK 6 or JDK 7 are specified as the source/binary format.</li> | |
<li>Select the Libraries tab and confirm that the Java platform is set to either JDK 1.6 or JDK 1.7. Click OK to close the Project Properties window.</li> | |
</ol> | |
<p>In this exercise you will create two Java packages and one Java class in each of the packages.</p> | |
<ol> | |
<li>Right-click the Source Packages node under the | |
AnnProcessor project node and choose New > Java Package.</li> | |
<li>Type <strong><tt>ann</tt></strong> for the Package Name and click Finish to create the new Java package.</li> | |
<li>Repeat the two previous steps to create a Java package named <strong><tt>proc</tt></strong>. | |
<p>After you create the two Java packages, the structure of the project should be similar to the following image.</p> | |
<img src="../../../images_www/articles/72/java/annotations/packages.png" alt="screenshot of Projects window showing Java packages" title="The structure of the project for the annotation processor." class="margin-around b-all"></li> | |
<li>Right-click the <tt>ann</tt> Java package and choose New > Java class.</li> | |
<li>Type <strong><tt>Handleable</tt></strong> for the Class Name. Click Finish.</li> | |
<li>Modify the new <tt>Handleable.java</tt> file to make the following changes. Save the file. | |
<pre>package ann; | |
public <strong>@interface</strong> Handleable { | |
}</pre> | |
<p>This is how annotations are declared, and it is quite similar to an interface declaration. | |
The difference is that the <tt>interface</tt> keyword must be preceded with an <tt>at</tt> sign (@). | |
This annotation is called <tt>Handleable</tt>.</p> | |
<p class="notes"><strong>Additional Information.</strong> In annotation declarations, you can also specify | |
additional parameters, for example, what types of elements can be annotated, e.g. classes or methods. | |
You do this by adding <tt>@Target(value = {ElementType.TYPE})</tt> for classes | |
and <tt>@Target(value = {ElementType.METHOD}).</tt> | |
So, the annotation declaration becomes annotated itself with <em>meta-annotations</em>. </p> | |
<p>You now need to add code for the annotation processor to process the <tt>Handleable</tt> annotation.<p> | |
</li> | |
<li>Right-click the <strong><tt>proc</tt></strong> Java package and choose New > Java class.</li> | |
<li>Type <strong><tt>HandleableProcessor</tt></strong> for the Class Name. Click Finish.</li> | |
<li>Modify the <tt>HandleableProcessor.java</tt> class to add the following code. Save your changes. | |
<p class="notes"><strong>Note.</strong> The value of <tt>@SupportedSourceVersion</tt> (in <strong>bold</strong>) will depend upon | |
the version of the JDK that you are using and will be either <tt>(SourceVersion.RELEASE_7)</tt> | |
or <tt>(SourceVersion.RELEASE_6)</tt>.</p> | |
<pre class="examplecode">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(<strong>SourceVersion.RELEASE_7</strong>) | |
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); | |
} | |
}</pre> | |
<p>Let's take a closer look at the main parts that constitute the code for the annotation processor | |
(note that for convenience, only parts of the code are provided). </p> | |
<p>At first, you specify the annotation types that the annotation processor supports | |
(by using <tt>@SupportedAnnotationTypes</tt>) and the version of the source files that are supported | |
(by using <tt>@SupportedSourceVersion</tt>), in this case the version is JDK 6: <br> | |
<pre class="examplecode"> | |
@SupportedAnnotationTypes("ann.Handleable") | |
@SupportedSourceVersion(SourceVersion.RELEASE_6)</pre> | |
<p>Then, you declare a public class for the processor that extends the <tt>AbstractProcessor</tt> | |
class from the <tt>javax.annotation.processing</tt> package. | |
<tt>AbstractProcessor</tt> is a standard superclass for concrete annotation processors that | |
contains necessary methods for processing annotations.</p> | |
<pre class="examplecode">public class HandleableProcessor extends AbstractProcessor { | |
... | |
}</pre> | |
<p>You now need to provide a public constructor for the class.</p> | |
<pre class="examplecode">public class HandleableProcessor extends AbstractProcessor { | |
<strong> public HandleableProcessor() { | |
}</strong> | |
... | |
}</pre> | |
<p>Then, you call the <tt>process</tt>() method of the parent <tt>AbstractProcessor</tt> class. | |
Through this method the annotations available for processing are provided. | |
In addition, this method contains information about the round of processing.</p> | |
<pre class="examplecode">public class HandleableProcessor extends AbstractProcessor {<strong> | |
</strong>... | |
<strong> public boolean process(Set<? extends TypeElement> annotations, | |
RoundEnvironment roundEnv) { | |
... | |
} | |
</strong> | |
}</pre> | |
<p>The annotation processor's logic is contained within the <tt>process()</tt> method of the <tt>AbstractProcessor</tt> class. | |
Note that through <tt>AbstractProcessor</tt>, you also access the <tt>ProcessingEnvironment</tt> interface, | |
which allows annotation processors to use several useful facilities, such as Filer | |
(a filer handler that enables annotation processors to create new files) and | |
Messager (a way for annotation processors to report errors).</p> | |
<pre class="examplecode">public class HandleableProcessor extends AbstractProcessor {<strong> | |
</strong>... | |
public boolean process(Set<? extends TypeElement> annotations, | |
RoundEnvironment roundEnv) {<br> | |
//For each element annotated with the Handleable annotation | |
<strong>for (Element e : roundEnv.getElementsAnnotatedWith(Handleable.class)) { | |
<br> </strong>//Check if the type of the annotated element is not a field. If yes, return a warning<strong>.<br> if (e.getKind() != ElementKind.FIELD) {<br> processingEnv.getMessager().printMessage(<br> Diagnostic.Kind.WARNING,<br> "Not a field", e);<br> continue;<br> } | |
</strong>//Define the following variables: name and clazz<strong>.</strong><strong><br> String name = capitalize(e.getSimpleName().toString());<br> TypeElement clazz = (TypeElement) e.getEnclosingElement();<br> </strong>//Generate a source file with a specified class name. <strong> | |
try {<br> JavaFileObject f = processingEnv.getFiler().<br> createSourceFile(clazz.getQualifiedName() + "Extras");<br> processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE,<br> "Creating " + f.toUri());<br> Writer w = f.openWriter();<br> </strong>//Add the content to the newly generated file<strong>. | |
try {<br> PrintWriter pw = new PrintWriter(w);<br> pw.println("package "<br> + clazz.getEnclosingElement().getSimpleName() + ";");<br> pw.println("public abstract class "<br> + clazz.getSimpleName() + "Extras {");<br> pw.println(" protected " + clazz.getSimpleName()<br> + "Extras() {}");<br> TypeMirror type = e.asType();<br> pw.println(" /** Handle something. */");<br> pw.println(" protected final void handle" + name<br> + "(" + type + " value) {");<br> pw.println(" System.out.println(value);");<br> pw.println(" }");<br> pw.println("}");<br> pw.flush();<br> } finally {<br> w.close();<br> }<br> } catch (IOException x) {<br> processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,<br> x.toString());<br> }<br> }</strong><br> return true; | |
<strong> }</strong> | |
... | |
}</pre> | |
<p>The last block in this code declares the <tt>capitalize</tt> method that is used to capitalize | |
the name of the annotated element.</p> | |
<pre class="examplecode">public class HandleableProcessor extends AbstractProcessor {<strong> | |
</strong>...<strong> | |
private static String capitalize(String name) {<br> char[] c = name.toCharArray();<br> c[0] = Character.toUpperCase(c[0]);<br> return new String(c);<br> } | |
</strong>}</pre> | |
</li> | |
<li>Build the project by right-clicking the <tt>AnnProcessor</tt> project and choosing Build.</li> | |
</ol> | |
<h2><a name="useprocessor"></a>Using the Annotation Processor in the IDE</h2> | |
<p>In this section you will create a Java Application project in which the annotation processor will be used.</p> | |
<ol> | |
<li>Choose File > New Project and select the Java Application project type in the Java category. Click Next.</li> | |
<li>In the Name and Location page, type <strong><tt>Demo</tt></strong> as the Project Name and specify the project location.</li> | |
<li>Type <strong><tt>demo.Main</tt></strong> in the Create Main Class field. Click Finish.<br> | |
<img src="../../../images_www/articles/72/java/annotations/demo-project-wizard.png" alt="screenshot of New Project wizard" title="Creating the Demo project in the New Project wizard." class="margin-around b-all"></li> | |
<li>Open the Project Properties window and confirm that either JDK 6 or JDK 7 are selected as the source/binary format in the | |
Sources panel and that the Java platform is set to JDK 1.6 or JDK 1.7 in the Libraries panel.</li> | |
<li>Modify the <tt>Main.java</tt> class to add the following code. Save your changes. | |
<pre class="examplecode">package demo; | |
<strong>import ann.Handleable;</strong> | |
public class Main <strong>extends MainExtras</strong> { | |
<strong>@Handleable | |
private String stuff;</strong> | |
<strong>public static void main(String[] args) { | |
new Main().handleStuff("hello"); | |
}</strong> | |
}</pre> | |
<p>This code contains the following elements:</p> | |
<ul> | |
<li>import statement for the custom annotation processor <tt>ann.Handleable</tt></li> | |
<li>the public class <tt>Main</tt> that extends the <tt>MainExtras</tt> class | |
(<tt>MainExtras</tt> should be generated by the annotation processor during compilation)</li> | |
<li>a private field named <tt>stuff</tt> that is annotated with the <tt>@Handleable</tt> annotation </li> | |
<li>the <tt>main</tt> method that calls the <tt>handleStuff</tt> method, | |
which is declared in the automatically generated <tt>MainExtras</tt> class | |
<p>In this simple example, the <tt>handleStuff</tt> method only prints out the current value. | |
You can modify this method to perform other tasks.</p></li> | |
</ul> | |
<p>After you save the <tt>Main.java</tt> code you will see that the IDE reports multiple compilation errors. | |
This is because the annotation processor has not been added yet to the project.</p> | |
</li> | |
<li>Right-click the <tt>Demo</tt> project node in the Projects window, choose Properties, | |
then select the Libraries category in the Project Properties window.</li> | |
<li>In the Compile tab, click Add Project and locate the <tt>AnnProcessor</tt> project.<br> | |
<img src="../../../images_www/articles/72/java/annotations/demo-properties-compile.png" alt="screenshot of Compile tab in Libraries category of the project's Properties window" title="Compile tab in Libraries category of the project's Properties window" class="margin-around b-all"> | |
<p>The Compile tab corresponds to the <tt>-classpath</tt> option of the | |
<a href="http://download.oracle.com/javase/6/docs/technotes/tools/windows/javac.html#options" target="_blank">Java compiler</a>. | |
Because the annotation processor is a single JAR file that contains both the annotation definition and the annotation processor, | |
you should add it to the project's classpath, which is the Compile tab.</p> | |
</li> | |
<li>Select the Compiling category in the Project Properties window | |
and select the Enable Annotation Processing and Enable Annotation Processing in Editor checkboxes.</li> | |
<li>Specify the annotation processor to run by click the Add button next to the Annotation Processors text area | |
and typing <strong><tt>proc.HandleableProcessor</tt></strong> in the Annotation Processor FQN field. <br> | |
<img src="../../../images_www/articles/72/java/annotations/demo-processor-fqn.png" alt="screenshot of Annotation Processor FQN dialog box" title="Annotation Processor FQN dialog box" class="margin-around b-all"> | |
<p>The Compiling category in the Project Properties window should look like the following image.</p> | |
<img src="../../../images_www/articles/72/java/annotations/demo-properties-compiling.png" alt="screenshot of Compiling category in the project's Properties window" title="Compiling category in the project's Properties window" class="margin-around b-all"> | |
</li> | |
<li>Click OK in the Properties window. | |
<p class="notes"><strong>Note.</strong> In the <tt>Main.java</tt> file you might still see compilation errors. | |
This is because the IDE cannot yet find the <tt>MainExtras.java</tt> file that declares the <tt>handleStuff</tt> method. | |
The <tt>MainExtras.java</tt> file will be generated after you build the Demo project for the first time. | |
If Compile On Save is enabled for you project, the IDE compiled the project when you saved <tt>Main.java</tt>.</p> | |
</li> | |
<li>Right-click the Demo project and choose Build. | |
<p>After you build the project, if you look at the project in the Projects window | |
you can see a new <tt>Generated Sources</tt> node with the <tt>demo/MainExtras.java</tt> file.</p> | |
<img src="../../../images_www/articles/72/java/annotations/demo-generated-sources.png" alt="screenshot of Projects window with Generated Sources" title="Projects window with Generated Sources" class="margin-around b-all"> | |
<p>If you review the contents of the generated <tt>MainExtras.java</tt> file, | |
you can see that the annotation processor generated the <tt>MainExtras</tt> class with the <tt>handleStuff</tt> method. | |
The <tt>handleStuff</tt> method is the one invoked from the annotated <tt>Main.java</tt> file. </p> | |
<pre class="examplecode">package demo; | |
public abstract class MainExtras { | |
protected MainExtras() {} | |
/** Handle something. */ | |
protected final void handleStuff(java.lang.String value) { | |
System.out.println(value); | |
} | |
}</pre> | |
</li> | |
<li>Right-click the Demo project and choose Run. | |
<p>When you click Run you should see the following in the Output window. | |
The Demo project compiles and prints the message.</p> | |
<img src="../../../images_www/articles/72/java/annotations/demo-run.png" alt="screenshot of Projects window with Generated Sources" title="Projects window with Generated Sources" class="margin-around b-all"> | |
</ol> | |
<div class="feedback-box"><a href="/about/contact_form.html?to=3&subject=Feedback:%20Using%20the%20Annotation%20Processors%20Support%20in%20NetBeans%20IDE">Send Feedback on This Tutorial</a><br style="clear:both;" /> | |
</div> | |
<h2><a name="seealso" id="seealso"></a>See Also</h2> | |
<p>See the following resources for more information about annotations in Java applications:</p> | |
<ul> | |
<li>Java SE Documentation - <a href="http://download.oracle.com/javase/6/docs/technotes/guides/language/annotations.html" target="_blank">Annotations</a></li> | |
<li>Java SE Tutorial - <a href="http://download.oracle.com/javase/tutorial/java/javaOO/annotations.html" target="_blank">Annotations</a> </li> | |
<li><a href="http://download.oracle.com/javase/6/docs/technotes/tools/windows/javac.html#processing" target="_blank">Java Compiler: Annotation Processing Options</a> </li> | |
<li><a href="http://blogs.oracle.com/darcy/">Joseph D. Darcy's Weblog</a> - useful tips from the JSR-269 specification lead </li> | |
</ul> | |
</body> | |
</html> |