Annotation Syntax


In this section, we cover everything you need to know about the annotation syntax.

An annotation is defined by an annotation interface:


modifiers @interface AnnotationName
{
   element declaration1
   element declaration2
   . . .
}

Each element declaration has the form


type elementName();

or


type elementName() default value;

For example, the following annotation has two elements, assignedTo and severity.

 public @interface BugReport {    String assignedTo() default "[none]";    int severity() = 0; } 

Each annotation has the format


@AnnotationName(elementName1=value1, elementName2=value2, . . .)

For example,

 @BugReport(assignedTo="Harry", severity=10) 

The order of the elements does not matter. The annotation

 @BugReport(severity=10, assignedTo="Harry") 

is identical to the preceding one.

The default value of the declaration is used if an element value is not specified. For example, consider the annotation

 @BugReport(severity=10) 

The value of the assignedTo element is the string "[none]".

CAUTION

Defaults are not stored with the annotation; instead, they are dynamically computed. For example, if you change the default for the assignedTo element to "[]" and recompile the BugReport interface, then the annotation @BugReport(severity=10) uses the new default, even in class files that have been compiled before the default changed.


Two special shortcuts can simplify annotations.

If no elements are specified, either because the annotation doesn't have any or because all of them use the default value, then you don't need to use parentheses. For example,

 @BugReport 

is the same as

 @BugReport(assignedTo="[none]", severity=0) 

Such an annotation is called a marker annotation.

The other shortcut is the single value annotation. If an element has the special name value, and no other element is specified, then you can omit the element name and the = symbol. For example, had we defined the ActionListenerFor annotation interface of the preceding section as

 public @interface ActionListenerFor {    String value(); } 

then we could have written the annotations as

 @ActionListenerFor("yellowButton") 

instead of

 @ActionListenerFor(value="yellowButton") 

All annotation interfaces implicitly extend the interface java.lang.annotation.Annotation. That interface is a regular interface, not an annotation interface. See the API notes at the end of this section for the methods provided by this interface.

You cannot extend annotation interfaces. In other words, all annotation interfaces directly extend java.lang.annotation.Annotation.

You never supply classes that implement annotation interfaces. Instead, the virtual machine generates proxy classes and objects when needed. For example, when requesting an ActionListenerFor annotation, the virtual machine carries out an operation similar to the following:


return Proxy.newProxyInstance(classLoader, ActionListenerFor.class,
   new
      InvocationHandler()
      {
         public Object invoke(Object proxy, Method m, Object[] args) throws Throwable
         {
            if (m.getName().equals("source")) return value of source annotation;
            . . .
         }
      });

The element declarations in the annotation interface are actually method declarations. The methods of an annotation interface can have no parameters and no throws clauses, and they cannot be generic.

The type of an annotation element is one of the following:

  • A primitive type (int, short, long, byte, char, double, float, or boolean)

  • String

  • Class (with an optional type parameter such as Class<? extends MyClass>)

  • An enum type

  • An annotation type

  • An array of the preceding types

NOTE

An array of arrays is not a legal element type.


Here are examples for valid element declarations:

 public @interface BugReport {    enum Status { UNCONFIRMED, CONFIRMED, FIXED, NOTABUG };    boolean showStopper() default false;    String assignedTo() default "[none]";    Class<? extends Testable> testCase() default Testable.class;    Status status() default Status.UNCONFIRMED;    TestCase testCase();    String[] reportedBy(); } 

Because annotations are evaluated by the compiler, all element values must be compile-time constants. For example,

 @BugReport(showStopper=true, assignedTo="Harry", testCase=MyTestCase.class,    status=BugReport.Status.CONFIRMED, . . .) 

CAUTION

An annotation element can never be set to null. Not even a default of null is permissible. This can be rather inconvenient in practice. You will need to find other defaults, such as "" or Void.class.


If an element value is an array, you enclose its values in braces, like this:

 @BugReport(. . ., reportedBy={"Harry", "Carl"}) 

You can omit the braces if the element has a single value:

 @BugReport(. . ., reportedBy="Joe") // OK, same as {"Joe"} 

Since an annotation element can be another annotation, you can build arbitrarily complex annotations. For example,

 @BugReport(testCase=@TestCase(), . . .) 

NOTE

It is an error to introduce circular dependencies in annotations. For example, if BugReport has an element of the annotation type TestCase, then TestCase can't have an element of type BugReport.


You can add annotations to the following items:

  • Packages

  • Classes (including enum)

  • Interfaces (including annotation interfaces)

  • Methods

  • Constructors

  • Instance fields (including enum constants)

  • Local variables

  • Parameter variables

However, annotations for local variables can only be processed at the source level. Class files do not describe local variables. Therefore, all local variable annotations are discarded when a class is compiled. Similarly, annotations for packages are not retained beyond the source level.

NOTE

If you want to process annotations of local variables, you have to write your own parser. The apt tool of the JDK (which we will discuss later in this chapter) does not visit local variables.


An item can have multiple annotations, provided they belong to different types. You cannot use the same annotation type more than once when annotating a particular item. For example,

 @BugReport(showStopper=true, reportedBy="Joe") @BugReport(reportedBy={"Harry", "Carl"}) void myMethod() 

is a compile-time error. If this is a problem, you can design an annotation whose value is an array of simpler annotations:

 @BugReports({    @BugReport(showStopper=true, reportedBy="Joe"),    @BugReport(reportedBy={"Harry", "Carl"})) void myMethod() 


 java.lang.annotation.Annotation 5.0 

  • Class<? extends Annotation> annotationType()

    returns the Class object that represents the annotation interface of this annotation object. Note that calling getClass on an annotation object would return the actual class, not the interface.

  • boolean equals(Object other)

    returns TRue if other is an object that implements the same annotation interface as this annotation object and if all elements of this object and other are equal to another.

  • int hashCode()

    returns a hash code that is compatible with the equals method, derived from the name of the annotation interface and the element values.

  • String toString()

    returns a string representation that contains the annotation interface name and the element values, for example, @BugReport(assignedTo=[none], severity=0)



    Core JavaT 2 Volume II - Advanced Features
    Building an On Demand Computing Environment with IBM: How to Optimize Your Current Infrastructure for Today and Tomorrow (MaxFacts Guidebook series)
    ISBN: 193164411X
    EAN: 2147483647
    Year: 2003
    Pages: 156
    Authors: Jim Hoskins

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net