Chapter 15 Annotations

1) Annoation /?n??te???n/  types present the information in a standard and structured way that is amenable to automated processing by tools. Annotation is centered on types in the package java.lang.annotation.

Example:

/*-------------------------------
  Created:          Jan 31 2005
  Created By:       James Gosling
  Last Modified:    Feb 9 2005
  Last Modified By: Ken Arnold
  Revision:         3
---------------------------------*/
public class Foo {
    // ...
}

could be represented by annotation type by:

@interface ClassInfo {
    String created();
    String createdBy();
    String lastModified();
    String lastModifiedBy();
    int revision();
}

@ClassInfo (
    created = "Jan 31 2005",
    createdBy = "James Gosling",
    lastModified = "Feb 9 2005",
    lastModifiedBy = "Ken Arnold",
    revision = 3
)
public class Foo {
    // ...
}

 

2) An annotation type may not explicitly declare that it extends another interface, but all annotation types implicitly extend the interface Annotation. An annotation type is not allowed to be a generic type. Finally, an annotation type is not allowed to directly, or indirectly, have an element of its own type. If an interface explicitly extends Annotation it is not an annotation typeand Annotation itself is not an annotation type. Similarly, if an interface declares that it extends an annotation type, that interface is not itself an annotation type. Extending or implementing an annotation type is pointless, but if you do it, the annotation type is just a plain interface with the declared set of methods (including those inherited from Annotation).

The methods declared in an annotation type are known as the elements of the annotation type. These elements are constrained by strict rules:

  • The type of the element can only be a primitive type, String, an enum type, another annotation type, Class (or a specific generic invocation of Class), or an array of one of the preceding types.

  • The element cannot declare any parameters.

  • The element cannot have a throws clause.

  • The element cannot define a type parameter (that is, it can't be a generic method).

  You could define the following annotation type that has a default revision number of 1.0:

@interface Revision {
    int major() default 1;
    int minor() default 0;
}

The Revision annotation type could be used to annotate a class or interfacewe show you how to enforce this a little lateror used by other annotation types. In particular we can redefine the ClassInfo annotation type to use it:

@interface ClassInfo {
    String created();
    String createdBy();
    String lastModified();
    String lastModifiedBy();
    Revision revision();
}

When we first created class Foo we might have used ClassInfo:

@ClassInfo (
    created = "Jan 31 2005",
    createdBy = "James Gosling",
    lastModified = "Jan 31 2005",
    lastModifiedBy = "James Gosling",
    revision = @Revision
)
public class Foo {
    // ...
}

Notice how the initialization expression for an element of an annotation type uses the annotation syntax. In this case @Revision initializes the revision element with the default values for major and minor. When Foo is later edited, the revision element would be changed accordingly, for example:

@ClassInfo (
    created = "Jan 31 2005",
    createdBy = "James Gosling",
    lastModified = "Feb 9 2005",
    lastModifiedBy = "Ken Arnold",
    revision = @Revision(major = 3)
)
public class Foo {
    // ...
}

 

  An annotation type can have zero elements, in which case it is called a marker annotationsimilar to a marker interface. For example, the annotation type java.lang.Deprecated is a marker annotation that identifies a program element that should no longer be used. The compiler can issue a warning when a program element annotated with @Deprecated is used, as could an annotation-aware development environment.

 

3) The program elements that can be annotated are all those for which modifiers can be specified: type declarations (classes, interfaces, enums, and annotation types), field declarations, method and constructor declarations, local variable declarations, and even parameter declarations.

  If the annotation type is a marker annotation or if all its elements have default values, then the list of initializers can be omitted. For example, you can mark a method as deprecated:

@Deprecated
public void badMethod() { /* ... */ }

Equivalently, you can just specify an empty list of initializers:

@Deprecated() public void badMethod() { /* ... */ }

  The order of initializers is not significant, but each element can only appear once. If an element has a default value then it need not appear, but you can include it if you want to override the default value with a specific one.

  If an element has an array type, then it is initialized with an array initializer expression. For example, an annotation to track the bug fixes applied to a class might look like this:

@interface BugsFixed {
    String[] bugIDs();
}

  The intent is that as each bug is fixed, its identifier is appended to the initializer list for bugIDs. Here's how it might be used:

@BugsFixed(bugIDs = { "457605", "532456"})
class Foo { /* ... */ }

  If an array has only a single element, then you can use a shorthand to initialize the array, dispensing with the braces around the array elements. For example, the first bug fixed in Foo could be annotated like this:

@BugsFixed(bugIDs = "457605")

  If an annotation type, like BugsFixed, has only a single element, then naming that element value allows for some additional shorthand:

@interface BugsFixed {
    String[] value();
}

  The first use of BugsFixed above can now be written simply as

@BugsFixed({ "457605", "532456"})

  If there is a single initializer expression, then it is assumed to initialize an element called value. If there is no such element by that name, then you will get a compile-time error. Combining this shorthand with the shorthand for arrays with one element, you can rewrite the second use of BugsFixed to be

@BugsFixed("457605")

  You can have more than one element in the annotation type and still call one of them value. If you do, and all other elements have default values, then you can still use the shorthand form to initialize the value element. However, once you have more than one initializer expression, you must explicitly name each element.

4) You can restrict the applicability of an annotation type by annotating it with the @Target annotation. An annotation on an annotation type is known as a meta-annotation.

The Target annotation type is one of a small number of annotation types defined in the java.lang.annotation package -- all the types mentioned here are in that package unless otherwise stated. Target is applied to annotation types, and controls where those types are themselves applicable. It has a single elementan array of the enum type ElementType which following convention is called value. ElementType represents the different kinds of program elements to which annotations can be applied, and defines the constants ANNOTATION_TYPE, CONSTRUCTOR, METHOD, FIELD, LOCAL_VARIABLE, PARAMETER, PACKAGE, and TYPE. The compiler will check that any annotation applied to a program element is allowed to be applied to that kind of program element.

The ClassInfo annotation type should only be applied to type declarations (classes, interfaces, enums, or annotation types), so it should be declared:

@Target(ElementType.TYPE)
@interface ClassInfo {
    String created();
    String createdBy();
    String lastModified();
    String lastModifiedBy();
    Revision revision();
}

Now if you tried to annotate a parameter declaration with ClassInfo, you'd get a compile-time error.

You can specify multiple element types when applying the Target annotation. For example, an annotation type that only applies to fields or local variables would be annotated with

@Target({ ElementType.FIELD, ElementType.LOCAL_VARIABLE })

 

5) Associated with every annotation type is a retention policy that determines when the annotation can be accessed. This retention policy is defined by the RetentionPolicy enum, and is controlled by the use of the Retention meta-annotation. There are three retention policy values:

  • SOURCE Annotations exist only in the source file, and are discarded by the compiler when producing a binary representation.

  • CLASS Annotations are preserved in the binary representation of the class, but need not be available at runtime.

  • RUNTIME Annotations are preserved in the binary representation of the class and must be available at runtime via the reflection mechanism.

 

6) There are currently only a few defined annotation types:

  • The meta-annotations @Target and @Retention.

  • The @Deprecated and @Documented annotations.

  • The @Inherited meta-annotation that indicates an annotation should be inherited. For example, if a class Foo is queried for a specific annotation type that is not present on Foo, but that annotation type has the @Inherited meta-annotation, then Foo's superclass will be queried, and so forth.

  • The @Override annotation, which informs the compiler that a method is meant to override an inherited method from a superclass. This allows the compiler to warn you if you mistakenly overload the method instead of overriding it (a common mistake).

  • The @SuppressWarnings annotation tells the compiler to ignore certain warnings, as defined by the strings used to initialize the annotation. Unfortunately, there is no predefined set of warning strings, meaning that interoperability between different compilers could be a problem.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章