Browse DevX
Sign up for e-mail newsletters from DevX


Learn to Use the New Annotation Feature of Java 5.0 : Page 4

Developers have always struggled to find ways of adding semantic data to their Java code. They had to: Java didn't have a native metadata facility. But that's all changed with version 5.0 of Java, which allows annotations as a typed part of the language.




Building the Right Environment to Support AI, Machine Learning and Deep Learning

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.

  • Annotations cannot extend other annotations, except for the java.lang.annotation.Annotation marker interface they inherently extend.
  • Method return types must be: primitive types, String, Class, enum types, annotation types, or arrays of the preceding types.
  • Annotations can't have a throws clause.
  • Self reference is not allowed (e.g. AnnotationA contains a member of type AnnotationA), nor circular reference (e.g. AnnotationA contains a member of type AnnotationB and vice versa).
  • Single member annotations must define only a single method called value in the annotation type. So long as you follow this construct, you can use the condensed single-member syntax when creating an annotation of this type.

    A single member annotation can be defined as follows:

    public @interface Copyright { String value(); }

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.

Javid Jamae consults for Valtech, a global consulting group specializing in delivering advanced technology solutions. Valtech endeavors to help its customers through its global delivery model to create and/or maintain an affordable competitive advantage.
Thanks for your registration, follow us on our social networks to keep up-to-date