Declaring Annotation Types and Annotating Source Code

Before you can annotate source code, you need annotation types that can be instantiated. Java supplies many annotation types in addition to Override, Deprecated, and SuppressWarnings. Java also lets you declare your own types.

You declare an annotation type by specifying the @ symbol, immediately followed by reserved word interface, followed by the type's name, followed by a body. For example, Listing 5-13 uses @interface to declare an annotation type named Stub.

Listing 5-13. Declaring the Stub annotation type public ^interface Stub

Instances of annotation types that supply no data apart from a name—their bodies are empty—are known as marker annotations because they mark application elements for some purpose. As Listing 5-14 reveals, @Stub is used to mark empty methods (stubs).

Listing 5-14. Annotating a stubbed-out method public class Deck // Describes a deck of cards. {

@Stub public void shuffle() {

// This method is empty and will presumably be filled in with appropriate // code at some later date.

Listing 5-14's Deck class declares an empty shuffle() method. This fact is indicated by instantiating Stub and prefixing shuffle()'s method header with the resulting @Stub annotation.

NOTE: Although marker interfaces (discussed in Chapter 3) appear to have been replaced by marker annotations, this is not the case, because marker interfaces have advantages over marker annotations. One advantage is that a marker interface specifies a type that is implemented by a marked class, which lets you catch problems at compile time. For example, if a class does not implement the Cloneable interface, its instances cannot be shallowly cloned via Object's clone() method. If Cloneable had been implemented as a marker annotation, this problem would not be detected until runtime.

Although marker annotations are useful (@Override and @Deprecated are good examples), you will typically want to enhance an annotation type so that you can store metadata via its instances. You accomplish this task by adding elements to the type.

An element is a method header that appears in the annotation type's body. It cannot have parameters or a throws clause, and its return type must be a primitive type (such as int), String, Class, an enum, an annotation type, or an array of the preceding types. However, it can have a default value.

Listing 5-15 adds three elements to Stub. Listing 5-15. Adding three elements to the Stub annotation type public @interface Stub {

int id(); // A semicolon must terminate an element declaration. String dueDate();

String developer() default "unassigned";

The id() element specifies a 32-bit integer that identifies the stub. The dueDate() element specifies a String-based date that identifies when the method stub is to be implemented. Finally, developer() specifies the String-based name of the developer responsible for coding the method stub.

Unlike id() and dueDate(), developer() is declared with a default value, "unassigned". When you instantiate Stub and do not assign a value to developer() in that instance, as is the case with Listing 5-16, this default value is assigned to developer().

Listing 5-16. Initializing a Stub instance's elements public class Deck {

public void shuffle() {

Listing 5-16 reveals one @Stub annotation that initializes its id() element to 1 and its dueDate() element to "10/21/2010". Each element name does not have a trailing (), and the comma-separated list of two element initializers appears between ( and ).

Suppose you decide to replace Stub's id(), dueDate(), and developer() elements with a single String value() element whose string specifies comma-separated ID, due date, and developer name values. Listing 5-17 shows you two ways to initialize value.

Listing 5-17. Initializing each Stub instance's value() element public class Deck {

@Stub(value = "1,10/21/2010,unassigned")

public void shuffle() {

@Stub("2,10/21/2010,unassigned")

public Card[] deal(int ncards) {

return null;

This listing reveals special treatment for the value() element. When it is an annotation type's only element, you can omit value()'s name and = from the initializer. I used this fact to specify @SuppressWarnings("deprecation") in Listing 5-12.

Was this article helpful?

0 0

Post a comment