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.
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.
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.
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
;
Table 7-2 summarizes common annotations supplied with Java.
Table 7-2. Standard annotations
Annotation | Description |
---|---|
| Deprecation warning on member |
Indicates that the annotated method must override a method in the parent class or else a compiler warning is issued | |
| 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 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.