Declaring Annotation Types
Now that you've learned a little about the annotations that come packaged with Java 1.5, you can move on to declaring your own annotation types.
Here is a sample annotation type:
public @interface MyAnnotationType {
int someValue();
String someOtherValue();
String yesSomeOtherValue() default "[blank]";
}
As you can see, annotation types are declared similarly to interfaces. In fact they use the
interface keyword prepended with an @ sign. Just like an interface, annotations have method declarations, each of which defines a
member of the annotation. These methods may not have any parameters. As shown in the example, default values are specified after the parenthesis on a method declaration.
At first, it seems a little odd to specify the members of an annotation using method syntax, because when you declare a Java element and annotate it (e.g. when you annotate a class), you may pass values into the annotation. But you are not the consumer of the annotation at this point; you are merely constructing an instance of the annotation. Think of it as calling a constructor on an implicit Java class that you didn't have to write.
The annotation consumers are the development tools, the compiler, or a runtime library that accesses the annotation data you created when you annotated your Java code. After you've created the annotation, annotation consumers may call the methods on the annotation interface in order to get the annotation values. The return types of the methods represent the type of data that a consumer of the annotation would get back.
There are a few restrictions when defining annotation types.
You can also create meta-annotations, as we have already seen. A meta-annotation is any annotation that can be used to annotate other annotations. For example, all of the build-in annotations utilize meta-annotations and some of them are meta-annotations themselves.
Here is the declaration for the @ Inherited meta-annotation type:
@Documented
@Retention(value=RUNTIME)
@Target(value=ANNOTATION_TYPE)
public @interface Inherited
The @Inherited annotation uses three other meta-annotations and is a meta-annotation itself. What makes it a meta-annotation? Any annotation whose @Target annotation member includes
ANNOTATION_TYPE can be used as a meta-annotation.
Reading Annotations
Now that you know how to declare your own annotation types and annotate Java elements, you need to know how to access the annotation data you specified. Annotation consumers are software that read annotation data and do something useful with it. Annotation consumers fall into three groups:
General tools are programs that can analyze source code and do something useful with it. For example compilers and documentation generators are both considered general tools. General tools do not load annotated classes or annotation interfaces into the virtual machine.
Specific tools are also programs that can analyze source code without loading annotated classes, but they need to load annotation interfaces into the virtual machine. An example of this is a Stub generator.
Introspectors are programs that can query their own annotations (the ones with a RUNTIME retention policy). Introspectors will load both annotated classes and annotation interfaces into the virtual machine.
Listing 1 is an example of how you can access your code during runtime using the reflection API.
As I mentioned previously, I think that most developers will be users of annotations, but few will have to write code that consumes annotations.
If you are a general or specific tools developer, you may want to look into a few APIs that will help you read annotations from source files in order to use them for some type of static preprocessing. The new Doclet API (com.sun.javadoc) has support for reading annotations. It doesn’t currently support all of the features of annotations, but it may suffice as a library for writing your tool. Another thing to keep an eye on is the newly submitted JSR-269 (Pluggable Annotation Processing API), which will provide a generic API that allows developers to read annotation data using general and specific tools.
If you are developing an introspector, you can use the new reflection API to access your annotations, though I would suggest looking into AOP as a means to interface with annotated methods. I think there is a lot of room for exploration here. The combinations of aspects and annotations can yield a very powerful introspection tool.