Annotations

As we mentioned in Chapter 4, Java for a long time has supported a limited kind of metadata in Java source code through the use of Javadoc comment tags. With Javadoc tags like @deprecated or @author, we can add some information to a class, method, or field by sticking it into comments above the item. In this case, the information is mainly useful to the Javadoc documentation generator, because comments exist only in Java source code. However, developers have long wanted a way to generalize metadata for other purposes. And in fact, some tools have been developed over the years that read extended Javadoc-style tags in comments and do all sorts of things with them, including code generation and documentation. In Java 5.0, a formal, extensible metadata system called annotations was added to the language that provides this kind of source-level functionality as well as new possibilities for using metadata at runtime.

Annotations allow you to add metadata to Java packages, classes, methods, and fields. This metadata can be utilized by tools at compile time and optionally retained in the compiled Java classes for use at runtime as well. The availability of annotation data to the running program opens up new uses for metadata. For example, annotations cannot only be used at compile time to generate auxiliary classes or resources, but also could be used by a server to provide special services to classes such as importing or exporting of values, security, or monitoring. Annotations will be used heavily in Java XML Binding (JAXB), the Java Servlets API, and Java Web Services (JAX-WS), as we’ll see later in the book. In those cases, annotations are used to simplify configuration and deployment information.

Technically, according to the spec, annotations are not supposed to “directly affect the semantics of a program.” However, that admonition is a little vague and there is some fear in the Java community that this facility will open a Pandora’s box of possible abuses. Hopefully, developers will use them with restraint.

Only a handful of “built-in” annotations are commonly used in Java and we’ll summarize them in this section. More built-in annotations are used with specialized packages such as those for web services and some are used in creating the annotations themselves. Creating your own annotations for use in your code is syntactically easy (essentially just like declaring an interface), but implementing the behavior for them via the compiler or a runtime system is a bit beyond the scope of this book, so we won’t cover that here. The JDK provides a framework tool called apt that can be used to implement source-level annotations that generate and compile code or resource files at compile time. Accessing annotation data at runtime is done via the Reflection API as described briefly earlier in this chapter.

Using Annotations

Annotations are placed in the code preceding the annotated item using an @ (at) symbol followed by the annotation class name. The @Deprecated annotation is an example of the simplest kind, a marker or flag annotation. A marker annotation indicates some semantics just by its presence. (In the case of @Deprecated, it means that the member is deprecated and the compiler should generate warnings if it is used.) To use the @Deprecated annotation, we place it before a Java class, method, or field like this:

    @Deprecated
    class OldClass { ... }

    class AgingClass 
    {
        @Deprecated 
        public someMethod() { ... }
        ...
    }

More generally, annotations may take “arguments” in an extended method-like syntax. Table 7-1 summarizes the possible variations.

Table 7-1. Use of arguments in annotations

Example

Description

@Deprecated

Marker annotation (no “data”)

@WarningMessage("Something about...")

Single argument

@TestValues( { "one", "two" } )

Array of arguments

@Author( first="Pat", last="Niemeyer" )

Named arguments

The first annotation in the table, @Deprecated, is a real annotation as described earlier; the remaining three are fictitious. To accept multiple values, an annotation may either use the curly brace ({}) array syntax or the more novel named argument syntax listed in the final example. The named syntax allows arguments to be passed in any order.

Package annotations

In the introduction, we mentioned that Java packages can be annotated. This raises the question of where one would place such an annotation, as there is ordinarily no location where we “declare” a Java package; we normally just use them implicitly. The answer is that by convention we can create a file named package-info.java and place it into the folder corresponding to the Java package. The file cannot contain Java classes, but should contain a package statement. Package annotations can be placed on this package statement. In the following example, we deprecate the whole package learningjava.oldstuff such that using any of its classes generates the deprecation warning.

// file: learningjava/service/package-info.java

/** 
 * We can put package comments here too! 
 */
@Deprecated
package learningjava.oldstuff;

Standard Annotations

Table 7-2 summarizes common annotations supplied with Java.

Table 7-2. Standard annotations

Annotation

Description

@Deprecated

Deprecation warning on member

@Override

Indicates that the annotated method must override a method in the parent class or else a compiler warning is issued

@SuppressWarnings(value=" type ")

Indicates that the specified warning types should be suppressed by the compiler for the annotated class or method

We have already discussed the @Deprecated and @Override annotations, the latter of which we covered in the section Overriding Methods. The @SuppressWarnings annotation is intended to have a compelling use in bridging legacy code with newer code using generics after Java 5.0, but some compilers may not implement it.

Additional annotations are supplied with Java as part of the java.lang.annotations package that are used to annotate only other annotations (they are really meta-annotations). For example, the java.lang.annotation.Retention annotation sets the retention policy for an annotation, specifying whether it is retained in the compiled class and loaded at runtime.

The apt Tool

The Java JDK ships with the command-line Annotation Processing Tool, apt, which is a sort of frontend to the javac compiler. apt uses pluggable annotation processors to process the annotations in source files before the code is compiled by javac. If you write your own source-level annotations, you can build a plug-in annotation processor for apt that will be invoked to process your annotations in the source code. Your annotation processor can be quite sophisticated, examining the structure of the source code (in a read-only fashion) through the supplied syntax tree (object model) and generating any additional files or actions that it wishes. If you generate new Java source files, they will be automatically compiled by javac for you. Running apt on a source file with no annotations simply falls through to javac.

Get Learning Java, 4th Edition now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.