JSR 269 in Mustang Build 57

The initial reference implementation of JSR 269 shipped as part of Mustang build 57! JSR 269 has two basic pieces, an API that models the Java programming language and an API for writing annotation processors. Those pieces are in the new packages javax.lang.model.\* and javax.annotation.processing, respectively. The JSR 269 functionality is accessed by using new options to the javac command. By including JSR 269 support, the javac command now acts analogously to the apt command in Sun's JDK 5.

To get an overview of annotation processing, see our 2005 JavaOne session on that topic.

Annotation processing is now enabled by default in javac; we designed our implementation of JSR 269 so that there should only be negligible speed impact on javac when no annotation processors are run. To just run annotation processing without compiling source code to class files, use the -proc:only option.

Writing your first annotation processor

Annotation processing is a form of meta-programming, that is, programming based on the structure of a program. However, for starters, let's consider a "Hello World" annotation processor:

import javax.annotation.processing.\*;
import static  javax.lang.model.SourceVersion.\*;
import javax.lang.model.element.\*;
import javax.lang.model.type.\*;
import javax.lang.model.util.\*;
import java.util.Set;

@SupportedAnnotationTypes("\*")	// Process all annotations
@SupportedSourceVersion(RELEASE_6)
public class HelloWorldProcessor extends AbstractProcessor {
    public boolean process(Set<? extends TypeElement> annotations,
			   RoundEnvironment roundEnv) {
	if (!roundEnv.processingOver())
	    processingEnv.getMessager().printNotice("Hello World");
	return false; // Don't claim any annotations
    }
}

To compile this program, add tools.jar to the classpath of javac:
javac -cp Path-to-tools.jar HelloWorldProcessor.java

(We plan to make adding tools.jar to the classpath more convenient in the future.) To run the annotation processor, use the new -processor option to javac:
javac -processor HelloWorldProcessor Foo.java

The output should include:

Note: Hello World
(HelloWorldProcessor can be run against HelloWorldProcessor.java; to do so, both tools.jar and the class files for HelloWorldProcessor need to be on the classpath.) This simple annotation processor doesn't actually examine the structure of a program, but it illustrates a few points about how to write and run annotation processors:
  • Annotation processors are run by javac before the input source files are compiled.
  • Annotation processors must implement the javax.annotation.processing.Processor interface to get registered with javac. This interface has methods that inform javac about what the annotation processor does, including what annotations it processes and what source version it supports.
  • Extending the javax.annotation.processing.AbstractProcessor class is a convenient way to write a processor since annotations can be used to provide the value the methods return. When extending AbstractProcessor, the only method that needs to be implemented is process.
  • A processor can get run multiple times in one javac invocation. If the test (!roundEnv.processingOver()) is removed, "Note: Hello World" will be printed twice. The javac infrastructure can call a processor's process method once per round. A round corresponds to analyzing a set of types.
  • Processors get access to resources, like a Messager, by getting helper objects from different environments. The ProcessingEnvironment (the processingEnv field in AbstractProcessor) provides round-independent utilities while the RoundEnvironment argument to process provides round-dependent ones.

Future Topics

"Hello World" just scratches the surface of what annotation processors can do! For example, annotation processors can
  • process annotations
  • recursively generate new source files and class files
  • analyze class files (try javac -Xprint java.lang.Object)
In future blog entries, I'll discuss these topics as well as providing a comparison between apt and JSR 269 annotation processing, best practices for writing and running annotation processors, suggestions on how to use JSR 269 visitors, and describing how the API copes with the expression problem.
Comments:

[Trackback] Joe just announced the next big thing in compilers. We have been working hard the last months to the get this ready. There's still a lot to be done, but you can actually run an annotation processor directly in javac. This is without hurting perfo...

Posted by Peter Ah&eacute;'s Weblog on October 21, 2005 at 01:43 PM PDT #

Joe, what's the rationale behind @SupportedAnnotationTypes? Why didn't you use a plain method #getSupportedAnnotationTypes? Or #supportsAnnotationType(AnnotationType). I'm afraid this is not a good use of annotations. That's like implementing @FileNameFilter("\*.jpg") public class Jpegs {}

Posted by Matthias Ernst on October 21, 2005 at 08:15 PM PDT #

Matthias, The <tt>"@SupportedFoo"</tt> annotations are used by the <tt>AbstractProcessor</tt> class to provide the data returned by the corresponding <tt>"getSupportedFoo"</tt> method of the <tt>Processor</tt> interface. Just having the interface methods is not convenient, as shown by the boilerplate code used for factories in <tt>apt</tt>. Just using annotations on a processor class without a method to call is not very type safe; there is no way to require a particular annotation be present on a class. The JSR 269 <tt>AbstractProcessor</tt> combines the best aspects of these two approaches; the type safety of implementing an interface is maintained with the convenience of using annotations to populate the returned data. If you don't like using annotations for this purpose, you can implement the <tt>Processor</tt> interface directly or override the <tt>AbstractProcessor</tt> methods. However, I think the 269 pattern here is very neat and useful; I certainly like using it for the annotation processors I write.

Posted by Joe Darcy on October 23, 2005 at 03:13 PM PDT #

Ok, I understand. So you're basically using the annotation because it has a more convenient syntax for returning a "constant" Set<String> than Java? In annotation land, a value can be short-hand for a singleton array, and AbstractProcessor does the array->set conversion. Things that could be expressed in Java, too, using a var-args method: AbstractProcessor: protected Set<String> set(String ... strings) { return Collections.immutableSet(new HashSet(Arrays.asList(strings))); } MyProcessor: public Set<String> getSupportedAnnotationTypes() { return set("\*"); } The method boiler-plate still sucks, though. Now if the annotation shorthand for implementing a parameterless interface method through a constant were in the language ...

Posted by Matthias on October 23, 2005 at 08:36 PM PDT #

Can I process annotations on local classes and anonymous classes by using Pluggable Annotation Processing API?

Posted by Manabu Nakamura on October 24, 2005 at 01:55 PM PDT #

Another reason for using annotations is that information about supported annotation types and source versions is data about the annotation processor, that is, meta-data.

Posted by Peter Ah&eacute; on October 25, 2005 at 03:35 PM PDT #

Concerning whether annotations on local and anonymous classes can be processed by JSR 269, the current answer is "no." However, we are considering adding the API elements needed to accommodate this. As a prerequisite, the JSR 269 language model can already describe local and anonymous classes with the NestingKind enum values (ANONYMOUS, LOCAL, MEMBER, or TOP_LEVEL) returned by TypeElement.getNestingKind.

Posted by Joe Darcy on October 26, 2005 at 02:22 PM PDT #

Will I be able to receive callbacks for instances previously annotated by a processed annotation? I am asking this to implement some @Wrapper annotation, such as @WeakReference, so that it replaces a declaration with a wrapping declaration and in any part of the code it uses the wrapped object it replaces it to a <code>get()</code> call. Do you think this will be possible with the new tool?

Posted by Aviad Ben Dov on February 03, 2006 at 04:59 PM PST #

Does 269 allow for source to be generated that replaces an input? I.e. can I process class Foo to generate class Foo (in the same package), and then pass that on to the normal compiler chain (or recurse)? It would be awesome if so!

Posted by Dave Minter on May 29, 2006 at 01:16 AM PDT #

No, neither apt nor JSR 269 allow source files being processed to be overwritten and replaced with processor-augmented content. Additional questions can be addressed in the annotation processing forum.

Posted by Joe Darcy on May 31, 2006 at 05:21 AM PDT #

Post a Comment:
Comments are closed for this entry.
About

darcy

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today
News

No bookmarks in folder

Blogroll