blob: 0b3e89bc8801ff75ba5a52fa23e15d1d8fc3fb37 [file] [log] [blame]
<!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 &gt; 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 &gt; 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 &gt; 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 &gt; 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&lt;? extends TypeElement&gt; 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&lt;? extends TypeElement&gt; 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&lt;? extends TypeElement&gt; 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> &quot;Not a field&quot;, 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() + &quot;Extras&quot;);<br> processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE,<br> &quot;Creating &quot; + 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(&quot;package &quot;<br> + clazz.getEnclosingElement().getSimpleName() + &quot;;&quot;);<br> pw.println(&quot;public abstract class &quot;<br> + clazz.getSimpleName() + &quot;Extras {&quot;);<br> pw.println(&quot; protected &quot; + clazz.getSimpleName()<br> + &quot;Extras() {}&quot;);<br> TypeMirror type = e.asType();<br> pw.println(&quot; /** Handle something. */&quot;);<br> pw.println(&quot; protected final void handle&quot; + name<br> + &quot;(&quot; + type + &quot; value) {&quot;);<br> pw.println(&quot; System.out.println(value);&quot;);<br> pw.println(&quot; }&quot;);<br> pw.println(&quot;}&quot;);<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 &gt; 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>