Thursday Sep 07, 2006

JDK 6 Build 97 and 98 JSR 269 API Changes

Compared to build 96, build 97 only contained an assortment of minor corrections and clarifications to the API, such as fixing typos and adding additional cross references to sections of the JLS. The most systematic change was updating the javadoc of the methods in the utility visitor classes to follow the recommended pattern for methods intended to be overridden: state the general method contract (in this case with {@inheritDoc}) following by "This implementation...". This pattern is discussed in Effective Java (Item 15: Design and document for inheritance or else prohibit it) and is used in the skeletal collection implementations.

Build 98

  • Tightened the specification of the Filer to disallow overwriting files in more situations.
  • Added a description of the discovery process to Processor.
  • Explicitly stated the language modeling hierarchy javax.lang.model.\* can be used for purposes other than annotation processing.

Monday Aug 21, 2006

JDK 6 Build 96 JSR 269 API Changes

Build 96 of JDK 6 include a few changes since build 95:
  • An originatingElements parameter was added to the Filer create methods. The originating elements serve as hints to the tool infrastructure to better manage dependencies; they are the types or packages (representing package-info files) which caused an annotation processor to attempt to create a new file. See the Filer specification for more information.

    This is a source compatible change, but a recompile of existing annotation processors which use a Filer is required.

  • Elements.getPackageOf(Element) was added.
  • Various minor specification changes:
    • Element.getSimpleName() result redefined for constructors and initializers
    • TypeParameterElement.getBounds() result when no explicit bound redefined.

Monday Aug 14, 2006

JDK 6 Build 95 JSR 269 API Changes

Build 95 of JDK 6 include a few changes since build 92:
  • The return type of the Filer.{create, get}Resource methods was changed from JavaFileObject to FileObject. This less-specific return type is more appropriate for files that are not being treated as source or class files by the annotation processing infrastructure.
  • The RoundEnvironment.getElementsAnnotatedWith methods were clarified to state that non-annotation types are illegal arguments.
  • The method PackageElement.isUnnamed was added so that the text of a package's name does not need to be inspected to determine if a package is unnamed.

Monday Jul 24, 2006

Mustang Build 92 JSR 269 API Changes

Build 92 of Mustang includes API changes from the JSR 269 public review draft:
  • The Filer methods return JSR 199 objects instead of a Writer or OutputStream. This revised Filer API gives clients more flexibility over how a file is written. There is also a getResource method to non-destructively read the contents of an existing file.
  • Annotation processing is supported on package-info files, which can hold package annotations. While classes and interfaces (and their contents) are the most commonly annotated entities, packages can be annotated as well so the annotation processing API should consider those annotations too. More broadly, the new API can also accommodate any additional kinds of entities that will be able to be annotated in future language versions (like superpackages in Dolphin?).

There are small code deltas to adapt existing annotation processing code to use the new API. For Filer uses:

  • The return type of createSourceFile was changed from Writer to JavaFileObject.
    Replace filer.createSourceFile() // Pre-build 92
    With filer.createSourceFile().getWriter() // Build 92 and later
  • The return type of createClassFile was changed from OutputStream to JavaFileObject.
    Replace filer.createClassFile() // Pre-build 92
    With filer.createClassFile().getOutputStream() // Build 92 and later
  • The createBinaryFile method was removed; its functionality can be gotten from createResource. The Filer.Location enum was removed and JavaFileManager.Location is used instead.
    Replace filer.createBinaryFile(loc, pkg, relPath) // Pre-build 92
    With filer.createResource(javaFileManagerLoc, pkg, relPath).getWriter() // Build 92 and later
  • The createTextFile method was removed; its functionality can be gotten from createResource.
    Replace filer.createTextFile(loc, pkg, relPath, charsetName) // Pre-build 92
    With filer.createResource(javaFileManagerLoc, pkg, relPath).getWriter() // Build 92 and later
    Or new OutputStreamWriter(filer.createResource(javaFileManagerLoc, pkg, relPath).getOutputStream(), charsetName) // Build 92 and later
For RoundEnvironment uses:
  • The getSpecifiedTypeElements method returning a Set<? extends TypeElement> was replaced with getRootElements returning a Set<? extends Element>.
    Replace roundEnv.getSpecifiedTypeElements() // Pre-build 92
    With typesIn(roundEnv.getRootElements()) // Build 92 transition
Whether or not it is reasonble to wrap getRootElements with ElementFilter.typesIn depends on the circumstances and what the processor is trying to do. Using the new API, processors should handle annotations on any kind of element. If a processor is only examining classes and interfaces, applying the typesIn filter is reasonable. If other kinds of elements need to be processed as well, the getKind method can be used to find out what an element is or a visitor can be written to implement element-specific or kind-specific operations.

Tuesday Jul 18, 2006

Mustang Build 91 JSR 269 API Changes

In build 91 of Mustang, to address bug 6425592 we added a method to RoundEnvironment:
Set<? extends Element> getElementsAnnotatedWith(Class<? extends Annotation> a)
which parallels the existing method
Set<? extends Element>getElementsAnnotatedWith(TypeElement a)

The new method is similar in spirit to the Element.getAnnotation; while it violates meta and base level separation, used with care, it can make programming more convenient.

Friday May 19, 2006

JSR 269 in public review

I'm happy to announce that JSR 269 is now in public review. Please send comments to

(The public review draft has several differences from the API specification and implementation in Mustang build 84:

  • The Filer methods return JSR 199 JavaFileObject objects instead of Writer and OutputStream objects.
  • The legal input names to the createSourceFile and createClassFile methods in Filer were expanded to include syntax for creating package-info files.
  • The method
    Set<? extends TypeElement> getSpecifiedTypeElements()
    was replaced with
    Set<? extends Element> getRootElements()
Several of these changes relate to enabling annotation processing on package-info files in additional to normal source and class files.)

Tuesday Jan 10, 2006

apt mirror API Open Sourced

I'm happy to announce that we have open sourced the apt mirror API. The classes and interfaces in com.sun.mirror.apt.\* introduced in Sun's JDK 5.0 are now available under a BSD license from the aptmirrorapi project; see the "Documents & files" page to download an archive of the source files.

By compiling the source files in the archive and creating the corresponding jar file, the resulting jar file can be used on a Java compiler's classpath instead of the tools.jar in Sun JDK when developing annotation processors.

Friday Oct 21, 2005

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
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

(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

The output should include:

Note: Hello World
(HelloWorldProcessor can be run against; 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.

Friday Aug 12, 2005

Annotation Processing Forum Created

To discuss annotation processing, consider using this newly created forum. Topics should include both apt-based processing as well as processing based on the forthcoming JSR 269.



« July 2016

No bookmarks in folder