Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
1 of 7
http://drdobbs.com/article/print?articleId=184406144&siteSectionName=jvm
janotate.txt
janotate.zip
Java 5.0 introduces "annotations" that integrate metadata technology directly into the language.
By J. Benton
July 01, 2005
URL:http://drdobbs.com/jvm/184406144
J. Benton is a professional Java programmer and computer science graduate student with research interest in
AI planning. He can be reached at j.benton@acm.org.
Java developers have long been able to add metadata to code using comment-eating tools such as Javadoc and
XDoclet. However, Java 5.0 introduces a language facility called "annotations" that integrates a metadata
technology directly into the language, providing a standard for giving attributes to declarations (see JSR-175,
(http://www.jcp.org/en/jsr/detail?id=175). To support annotations, Sun Microsystems released apt, an
"Annotation Processing Tool" that lets you write your own annotation processors (http://java.sun.com/j2se/1.5.0
/docs/guide/apt/GettingStarted.html). This makes it possible for you to build programs that act upon annotations
for analyzing Java source files and automatically generating boilerplate code. It does this by providing the mirror
API, which provides functionality similar to the reflection API built into the Standard Java libraries. In this
article, I examine annotations and show how you use apt to analyze Java source files and generate boilerplate
code.
You use annotations just as you would any modifying keyword (final, static, transient, and the like), except you
put "@" in front of it. Each annotation has a set of intended declaration targets. That is, an annotation is intended
to be placed before a package, type (including class, enum, and interface), field (including an enum constant),
constructor, method, parameter, local variable declaration, or any combination of these. Three types of
annotations exist within Java, each with slightly different syntax. Table 1 describes each type.
java.lang Annotations
Syntax always gets clearer as you see examples of real usage. Happily, J2SE 5.0 supplies annotations built into
the API to explore. Three are intended to be used by Java compilers and defined in java.lang, so no import is
2/18/2012 5:37 PM
2 of 7
http://drdobbs.com/article/print?articleId=184406144&siteSectionName=jvm
Meta Annotations
An annotation type defines annotations, just as an interface defines an object. In fact, annotation types exist as
interfaces and act like them in some respects. They automatically extend the java.lang.annotation.Annotation
interface and have methods with return types. Their methods can only return primitive types, strings, enums,
another annotations, and arrays of those things.
In addition to the three previous annotation classes in the java.lang package, four are defined in
java.lang.annotation. All the annotations in that package are meta annotationsannotations that annotate
annotation types.
@Retention. Annotations can have one of three retention policies in Java 5.0. Annotations having
"source" retention (RetentionPolicy.SOURCE) exist only in source code and don't get compiled into
bytecode. Annotations with "class" retention (RetentionPolicy.CLASS) are intended to be read at the
bytecode level, after compilation and before runtime. Finally, runtime retention
(RetentionPolicy.RUNTIME) indicates that an annotation can be accessed through reflection at runtime. I
focus on annotations with "source" retention because apt is a source-level processing tool.
@Target. I previously described the type of targets. You can specify a single target using a single value or
2/18/2012 5:37 PM
3 of 7
http://drdobbs.com/article/print?articleId=184406144&siteSectionName=jvm
multiple ones using an array. Also, giving an empty array to an annotation of this type holds special value.
It forces you to use annotation types only as a return type within other annotation types. The apt examples
show why this is sometimes necessary when you want multiple annotations of the same type to be given
on a single item.
@Documented. The @Documented meta annotation is intended for use by document-generation tools like
javadoc. Javadoc generates documentation for an annotation type if, and only if, this meta annotation is
applied to it.
@Inherited. As meta annotations go, @Inherited probably ranks as the most interesting (although it is also
excluded from the apt examples for simplicity). It lets annotations be inherited by subclasses of the
annotated class. If an annotation type uses this meta annotation, any type (including classes, interfaces,
and enums) that it annotates lets this annotation be inherited to its subtypes. This is an "if and only if"
conditionif you don't want subtypes to inherit this annotation, then don't use it. (Annotations are
inherited on the annotation types themselves. Overridden methods will not inherit annotations.)
2/18/2012 5:37 PM
4 of 7
http://drdobbs.com/article/print?articleId=184406144&siteSectionName=jvm
have the ability to override the additional information given in the example, so you add -AIgnoreAddedInfo as a
supported option. The list only adds the convenience of checking the "supported options" against the options
provided to apt. All of apt's own options and those starting with an -A, whether supported or not, get passed to
the processor through environment.
In the example, the method getFactoryFor() works in a straightforward manner. It checks that the given
supported options match those given to apt. After that, it goes through the annotations that apt has found that the
annotation processor also claims to support (given through the atds set). Once it finds
com.ddj.annotations.ApplicationExceptions, it returns the proper annotation processor. If it fails to find the
suitable annotation, it returns a NO_OP annotation. Use NO_OP whenever you want to return an annotation
processor that does nothing.
Also in ApplicationExceptionsApf.java is the annotation processor itself. It goes into the processor factory class
as a static inner class. If you're familiar with Java reflection, you recognize the methods used to analyze the
code. Sun's mirror API works much like reflection, except it refers to source code rather than loaded classes and,
therefore, works on types and declarations. Table 3 shows each package in the mirror API and a short
description of each.
The processor is simple. It first looks at each type declaration given to the apt environment. It then gets the
ApplicationExceptions annotation and processes each ApplicationException value within, generating a .java file
containing the appropriate exception definition.
Next, you'll need to use this annotation processor. apt provides two ways of doing this: You can either use apt's
built-in annotation processor factory discovery facility, or specify the processor on a command line. You'd use
the discovery procedure when you have more than one annotation processor factory. Because only one
annotation processor factory exists here, I stick to the command line. You can use the discovery procedure by
putting a file called "META-INF/services/com.sun.mirror.apt.AnnotationProcessorFactory" in a .jar file that lists
each annotation processor factory that you created. The .jar file also needs to contain all factories listed and their
processors. You then can put the .jar file in your class path and apt tries to choose the proper factory for each
.java file you're processing, based upon supported annotations you list within each factory.
Listing Three is an example of using the ApplicationExceptions class. Again, I use a command-line option to
generate and execute the annotation processor. Before executing the following command, make sure the tools.jar
file is in your classpath and that you've compiled the annotation processor factory:
apt -factory com.ddj.apt.processors.
ApplicationExceptionsApf com\ddj\*.java
This should have generated two files: TestException.java contains an extra integer and AppException.java exists
as a plain extension to Exception.
Conclusion
In this article, I introduced the annotations built into J2SE 5.0 and looked at how you can use apt to generate
boilerplate exception code. I encourage you to expand upon the code. It's important to note, however, that apt's
days may be numbered. The recently approved JSR-269, the Pluggable Annotation Processing API, expressly
states that it is intended to supersede Sun's mirror API and apt. If it stays on schedule, it will likely ship with Java
6.0 (code-named "Mustang").
DDJ
2/18/2012 5:37 PM
5 of 7
http://drdobbs.com/article/print?articleId=184406144&siteSectionName=jvm
Listing One
/* ApplicationException.java * Created on Jan 2, 2005
package com.ddj.annotations;
*/
import java.lang.annotation.*;
/** This annotation is used by the annotation processing tool (apt)
* to generate an exception. * @author J. Benton */
@Retention(RetentionPolicy.SOURCE)
// I give an empty array to "@Target" to say that this annotation
// type should be used only as an element of other annotations
// (you cannot use this to annotate anything directly).
@Target({})
public @interface ApplicationException {
/** What I want to call this exception (sans the word "Exception".*/
String exceptionName();
/** I must add extra information to this exception to make it useful. */
String addedInformationType() default "";
/** I should call the "extra information" something that is recongizable if
* you try to read the generated exception class. */
String addedInformationVariableName() default "";
}
Back to article
Listing Two
/* ApplicationExceptions.java * Created on Jan 2, 2005 */
package com.ddj.annotations;
import java.lang.annotation.*;
/** This was made so I can generate a set of exceptions for an application
* on the main application class. * @author J. Benton */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
@Documented
public @interface ApplicationExceptions {
/** An array of ApplicationExceptions. I do things this way because we can't
* have more than one instance of the same annotation type on any item. */
ApplicationException[] applicationExceptions();
}
Back to article
Listing Three
/* ExceptionAnnotationTest.java * Created on Jan 3, 2005 */
package com.ddj;
import com.ddj.annotations.*;
/** Use this to test the annotations. * @author J. Benton */
@ApplicationExceptions(
applicationExceptions={@ApplicationException(exceptionName="Test",
addedInformationType="int",
addedInformationVariableName="status"),
@ApplicationException(exceptionName="App")})
public class ExceptionAnnotationTest {
}
Back to article
2/18/2012 5:37 PM
6 of 7
http://drdobbs.com/article/print?articleId=184406144&siteSectionName=jvm
2/18/2012 5:37 PM
7 of 7
http://drdobbs.com/article/print?articleId=184406144&siteSectionName=jvm
Annotation
Description
Example Syntax
Marker
Takes no values
@MarkerAnnotation
@SingleValuedAnnotation("VALUE")
Table 1: Annotations get addressed differently depending upon the number of values they take.
Options
Description
none
Give no warnings.
unchecked
path
serial
finally
fallthrough
Make sure you break after each case statement that would otherwise fall through to the next case
statement in a switch.
com.sun.mirror.apt
Provides classes that interact directly with the tool and its data.
com.sun.mirror.util
2/18/2012 5:37 PM