Java Basics
Java Annotation Facility - A Primer
JDK 5 Has Changed Source Code Generation in a Seminal Way
Mar. 9, 2005 12:00 AM
The 5.0 release of JDK introduced a slew of new features. A powerful technique that resulted from the JSR-175 recommendation is the Program Annotation Facility. It can annotate code in a standard way and automate the generation of source code or configuration files, helping cut down on boilerplate code.
At the moment, the closest thing to annotating source and generating support file/code is through java doc tags. The popular ones are @deprecated, @author, @param etc. However, these tags are pretty static by nature and the information they define isn't encoded in the class file by the compiler so it's not available at runtime. A popular implementation of this concept is XDoclet. This is an Open Source utility that lets a developer add metadata or attributes to source as java doc tags. Appropriate source files or configurations, such as deployment descriptors, are generated later using the ANT task provided by XDoclet. (The source code can be downloaded from www.sys-con.com/java/sourcec.cfm.)
The core Java language has always had some form of ad hoc annotation scheme. Java doc tags are an example. Another example is the keyword transient, which is used to mark a member variable so it can be ignored by the serialization subsystem.
All this changed with the introduction of JDK 5.0, which adds a general-purpose customizable annotation mechanism. This facility consists of syntax for declaring annotation types, syntax for annotating declarations, APIs for reading annotations, a class file representation for annotations and an annotation-processing tool.
Annotation and Annotation Types
The first step in the process is defining an annotation type. This is pretty simple to do and looks familiar as well. An annotation-type declaration looks like an interface declaration except an "@" symbol precedes the interface keyword. The method declaration that goes between the braces of this declaration defines the elements of the annotation type. Of course, since we are annotating the code and not defining behavior, logically speaking, these methods shouldn't throw any exception. That means no throws clause. Another restriction is that the return type for these methods is restricted to primitives: String, Class, enums, annotations and arrays of the preceding types. The complete lists of restrictions are as follows:
- No extends clause is permitted.Annotation types automatically extend a marker interface, java.lang.annotation.Annotation.
- Methods must not have any parameters.
- Methods must not have any type parameters (in other words, generic methods are prohibited).
- Method return types are restricted to primitive types: String, Class, enum types, annotation types and arrays of the preceding types.
- No throws clause is permitted.
- Annotation types must not be parameterized.
The following code snippet defines an annotation type for a servlet. Presumably, we could use this definition to annotate a servlet and then have an annotation tool generate web.xml. Here we define no args methods that define the various XML attributes/elements found in web.xml. For conciseness we have left out elements like init, load on startup, icon etc.
public @interface Servlet {
String servletName();
String servletClass();
String displayName();
String description();
}
Declaring Annotation
Now that we have the annotation-type defined we can annotate our servlet using the defined annotation type. Annotation is a new kind of modifier that contains an annotation type with zero or more member-value pairs. If a member has a default value defined in the annotation-type member declaration then the value can be omitted, otherwise, annotation must provide a member-value pair for all members defined in the annotation type. Annotation can be used for modifiers in any declaration - class, interface, constructor, method, field, enum, even local variable. It can also be used on a package declaration provided only one annotation is permitted for a given package. In our case we are annotating at the class level and the annotation precedes the access modifier public.
@Servlet(
servletName="AnnotatedServet",
servletClass="com.jdj.article.servlet.AnnotatedServet",
displayName="AnnotatedServet",
description="This is an example Annotated Servlet"
)
public class AnnotatedServet extends HttpServlet{...}
Now, to tie all these together we will look at how to build a simple annotation-driven framework. However, before we start looking at concrete code samples, we will go over a bit more of the theory behind this important addition to the core language API.
Meta Annotation Types
The API provides some annotation types out-of-the-box that can be used to annotate the annotation types. These standard annotation types are also known as meta-annotation types. The details are provided in Table 1.
Standard Annotation
The Tiger release of the JDK also bundles a set of standard annotation types. Table 2 defines the annotation tags and their purpose.
Annotation Retention
The consumers of annotation fall into three categories.
- Introspectors: Programs that query runtime-visible annotations of their own program elements. These programs will load both annotated classes and annotation interfaces into the virtual machine.
- Specific Tools: Programs that query known annotation types of arbitrary external programs. Stub generators, for example, fall into this category. These programs will read annotated classes without loading them into the virtual machine, but will load annotation interfaces.
- General Tools: Programs that query arbitrary annotations of arbitrary external programs (such as compilers, documentation generators and class browsers). These programs will load neither annotated classes nor annotation interfaces into the virtual machine.
The grouping of annotation consu-mers mentioned above is determined by the retention policy that is specified by the RetentionPolicy enum present in the java.lang.annotation package. If the retention policy is 'CLASS' then the annota-tions are recorded in the class files but are not retained by the virtual machine. If the retention policy is 'RUNTIME' then the annotations are recorded in the class file and are retained by the VM at runtime. The value 'SOURCE' causes the compiler and VM to discard the annotation.