How To Process Java Annotations

One of the cool new features of Java 8 is the support for lambda expressions. Lambda expressions lean heavily on the FunctionalInterface annotation.

In this post, we’ll look at annotations and how to process them so you can implement your own cool features.

Annotations

Annotations were added in Java 5. The Java language comes with some predefined annotations, but you can also define custom annotations.

Many frameworks and libraries make good use of custom annotations. JAX-RS, for instance, uses them to turn POJOs into REST resources.

Annotations can be processed at compile time or at runtime (or even both).

At runtime, you can use the reflection API. Each element of the Java language that can be annotated, like class or method, implements the AnnotatedElement interface. Note that an annotation is only available at runtime if it has the RUNTIME RetentionPolicy.

Compile-Time Annotation Processing

Java 5 came with the separate apt tool to process annotations, but since Java 6 this functionality is integrated into the compiler.

You can either call the compiler directly, e.g. from the command line, or indirectly, from your program.

In the former case, you specify the -processor option to javac, or you use the ServiceLoader framework by adding the file META-INF/services/javax.annotation.processing.Processor to your jar. The contents of this file should be a single line containing the fully qualified name of your processor class.

The ServiceLoader approach is especially convenient in an automated build, since all you have to do is put the annotation processor on the classpath during compilation, which build tools like Maven or Gradle will do for you.

Compile-Time Annotation Processing From Within Your Application

You can also use the compile-time tools to process annotations from within your running application.

Rather than calling javac directly, use the more convenient JavaCompiler interface. Either way, you’ll need to run your application with a JDK rather than just a JRE.

The JavaCompiler interface gives you programmatic access to the Java compiler. You can obtain an implementation of this interface using ToolProvider.getSystemJavaCompiler(). This method is sensitive to the JAVA_HOME environment variable.

The getTask() method of JavaCompiler allows you to add your annotation processor instances. This is the only way to control the construction of annotation processors; all other methods of invoking annotation processors require the processor to have a public no-arg constructor.

Annotation Processors

A processor must implement the Processor interface. Usually you will want to extend the AbstractProcessor base class rather than implement the interface from scratch.

Each annotation processor must indicate the types of annotations it is interested in through the getSupportedAnnotationTypes() method. You may return * to process all annotations.

The other important thing is to indicate which Java language version you support. Override the getSupportedSourceVersion() method and return one of the RELEASE_x constants.

With these methods implemented, your annotation processor is ready to get to work. The meat of the processor is in the process() method.

When process() returns true, the annotations processed are claimed by this processor, and will not be offered to other processors. Normally, you should play nice with other processors and return false.

Elements and TypeMirrors

The annotations and the Java elements they are present on are provided to your process() method as Element objects. You may want to process them using the Visitor pattern.

The most interesting types of elements are TypeElement for classes and interfaces (including annotations), ExecutableElement for methods, and VariableElement for fields.

Each Element points to a TypeMirror, which represents a type in the Java programming language. You can use the TypeMirror to walk the class relationships of the annotated code you’re processing, much like you would using reflection on the code running in the JVM.

Processing Rounds

Annotation processing happens in separate stages, called rounds. During each round, a processor gets a chance to process the annotations it is interested in.

The annotations to process and the elements they are present on are available via the RoundEnvironment parameter passed into the process() method.

If annotation processors generate new source or class files during a round, then the compiler will make those available for processing in the next round. This continues until no more new files are generated.

The last round contains no input, and is thus a good opportunity to release any resources the processor may have acquired.

Initializing and Configuring Processors

Annotation processors are initialized with a ProcessingEnvironment. This processing environment allows you to create new source or class files.

It also provides access to configuration in the form of options. Options are key-value pairs that you can supply on the command line to javac using the -A option. For this to work, you must return the options’ keys in the processor’s getSupportedOptions() method.

Finally, the processing environment provides some support routines (e.g. to get the JavaDoc for an element, or to get the direct super types of a type) that come in handy during processing.

Classpath Issues

To get the most accurate information during annotation processing, you must make sure that all imported classes are on the classpath, because classes that refer to types that are not available may have incomplete or altogether missing information.

When processing large numbers of annotated classes, this may lead to a problem on Windows systems where the command line becomes too large (> 8K). Even when you use the JavaCompiler interface, it still calls javac behind the scenes.

The Java compiler has a nice solution to this problem: you can use argument files that contain the arguments to javac. The name of the argument file is then supplied on the command line, preceded by @.

Unfortunately, the JavaCompiler.getTask() method doesn’t support argument files, so you’ll have to use the underlying run() method.

Remember that the getTask() approach is the only one that allows you to construct your annotation processors. If you must use argument files, then you have to use a public no-arg constructor.

If you’re in that situation, and you have multiple annotation processors that need to share a single instance of a class, you can’t pass that instance into the constructor, so you’ll be forced to use something like the Singleton pattern.

Conclusion

Annotations are an exciting technology that have lots of interesting applications. For example, I used them to extract the resources from a REST API into a resource model for further processing, like generating documentation.

I’m very interested to learn what you have used them for. Please leave a comment below.

Advertisement

System dependencies

I’m so happy to be developing in Java. It takes away the drudgery of software development, like memory management. And it frees you of worrying about how certain features are implemented on different platforms: Write Once, Run Anywhere!

You do feel the but coming, don’t you? 😉

Well, sometimes I do run into system dependencies. And since I’m no longer used to it, I don’t expect it anymore. Ah well, this happens only once in a very, very little while. Let me tell you about one such event.

I described in my previous post how I used reflection to extract common code into a base class. I used Class.getMethods(), for which the JavaDoc reads:

public Method[] getMethods() throws SecurityException

Returns an array containing Method objects reflecting all the public member methods of the class or interface represented by this Class object, including those declared by the class or interface and those inherited from superclasses and superinterfaces. Array classes return all the (public) member methods inherited from the Object class. The elements in the array returned are not sorted and are not in any particular order. This method returns an array of length 0 if this Class object represents a class or interface that has no public member methods, or if this Class object represents a primitive type or void.

The interesting part is in italic. This is one of those sentences that you can easily overlook. I know I did.

What does it mean? Nothing more than that the order is undefined in the spec, and so depends on the system (in this case the particular JVM implementation) that you use. We use both Windows and GNU/Linux to test our stuff, but on both we have a Sun JVM. I guess most people will use this one too, since it’s from the makers of Java and it’s free (as in beer and now also as in speech).

But not IBM. For their AIX platform, they have built a custom JVM. And you guessed right: that JVM uses a different order for the methods in the array. Whereas the Sun implementation always gives you methods from the class, then those from it’s base class, etc. the IBM implementation uses the exact reverse order. My code subtly depended on that order, and so it failed on AIX.

BTW, if you want to find out more about which JVM implementation you are using, just issue java -version. This is from my machine at home:

java version "1.6.0_06"
Java(TM) SE Runtime Environment (build 1.6.0_06-b02)
Java HotSpot(TM) Server VM (build 10.0-b22, mixed mode)

The HotSpot part is what gives away that it’s from Sun. This is from our AIX box:

java version "1.5.0"
Java(TM) 2 Runtime Environment, Standard Edition (build
    pap64dev-20080315 (SR7))
IBM J9 VM (build 2.3, J2RE 1.5.0 IBM J9 2.3 AIX
    ppc64-64 j9vmap6423-20080315 (JIT enabled)
J9VM - 20080314_17962_BHdSMr
JIT  - 20080130_0718ifx2_r8
GC   - 200802_08
JCL  - 20080314

Big Refactoring: Separate Domain from Presentation

In his landmark book Refactoring: Improving the Design of Existing Code, Marting Fowler not only presents a catalog of “regular” refactorings, he also mentions some “big” refactorings. These big refactorings are not described as a series of atomic steps to follow, but more as a recipe for using a longer series of regular refactorings. And since they are bigger than regular refactorings, they also take a lot longer to complete, sometimes even months.

I’m in the middle of one of these: Separate Domain from Presentation. Now, we all know that we shouldn’t put business logic in interface code, so why do I find myself in this situation?

Well, technically, I don’t 😉 We use Struts, which has a nice MVC architecture. However, it’s the Controller part that has me worried. In Struts, one writes Action classes to control application flow:

“The goal of an Action class is to process a request, via its execute() method, and return an ActionForward object that identifies where control should be forwarded (e.g. a JSP, Tile definition, Velocity template, or another Action) to provide the appropriate response.”

It is, however, all too convenient to implement the business logic in Action classes as well. The Struts documentation even warns about this danger:

“Perform the processing required to deal with this request (such as saving a row into a database). This can be done by logic code embedded within the Action class itself, but should generally be performed by calling an appropriate method of a business logic bean.”

And that’s exactly what’s happened in our code. So I guess I’m actually in the middle of Separate Domain from Controller 😉

Fixing this is not a trivial task. The Action classes use ActionForm classes that hold data entered in the UI to perform their work. This ties them to Struts, which I don’t like at all. For instance, it makes it very hard for us to switch to a different web framework, should we so choose. It also means that simple solutions like Extract Method won’t work, since the extracted method would get the ActionForm as a parameter.

My solution has been to introduce what I call Service classes. A Service class has one method that implements the service that the Action provides. The method has one parameter, which is a Parameter Object, that contains the same information as the Action‘s ActionForm does. I call them Service classes, since these classes could very well be used to implement web services as well.

Anyway, all the Action class has to do now, is:

  1. instantiate the appropriate Parameter Object
  2. populate it from the ActionForm
  3. instantiate the appropriate Service class
  4. call the appropriate method on the Service class (passing the Parameter Object)
  5. update the ActionForm from the method’s result object
  6. construct an ActionForward (possibly using information from the result object)

Luckily, I could automate all of that in a base class using reflection, so that each Action class now only needs two methods: one for instantiating the Parameter Object, and one for instantiating the Service class.

Still, that leaves a lot of Actions to convert. And to make matters worse, they are organized into class hierarchies, which makes it hard to convert them one by one. So I guess I won’t be sitting idle any time soon…