As we can annotate classes, we can also annotate custom annotations
Meta-annotations or annotations on annotations are helpful in figuring out someone else’s intent for a customized annotations
There are four standard meta-annotations, all defined in the java.lang.annotation package
o Target
Specifies which program elements can have annotations of the defined type
o Retention
Indicates whether an annotation is tossed out by the compiler, or retained in the compiled class file
In cases where the annotation is retained, it also specifies whether it is read by the JVM at class load
o Documented
Indicates that the defined annotation should be considered as part of the public API of the annotated program element
o Inherited
It is intended for use on annotation types that are targeted as classes, indicating that the annotated type is an inherited one
Target
It is used to specify which program elements are allowed as targets for the defined annotation
This prevents misuse of an annotation, and is a sanity check for an annotation
Target should be used in the lines directly preceding the annotation definition
@Target({ElementType.TYPE, ElementType.METHOD
ElementType.CONSTRUCTOR, ElementType.ANNOTATION_TYPE})
public @interface TODO {
....
}
Target takes a single member whose type is an array of values, each of which should be an enumerated value from the java.lang.annotation.ElementType enum
This enum defines the various program elements allowed as targets of an annotation type
package java.lang.annotation;
public enum ElementType {
TYPE,
FIELD,
METHOD,
PARAMETER,
CONSTRUCTIR,
LOCAL_VARIABLE,
ANNOTATION_TYPE,
PACKAGE
}
To use Target we need to import both Target and ElementType
Following is the definition for the Target annotation
package java.lang.annotation;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
ElementType[] value();
}
As we can see in the above definition, Target meta-annotation is used on itself
In case of annotation types that work for all program elements, we don’t have to use Target at all
Retention
The Retention meta-annotation defines how the Java compiler treats annotations
Annotations can be tossed out of a compiled class file by the compiler, or kept in the class file
Additionally, the JVM can ignore annotations – when they are retained in the class file, or read those annotations at the time a class is first loaded
All of these options are specified by Retention
Like Target, we specify the retention of an annotation type just before the annotation definition
Also like Target, the argument to Retention must be a value from an enum support class – java.lang.annotation.RetentionPolicy
package java.lang.annotation;
public enum RetentionPolicy {
SOURCE, //annotation is discarded by compiler
CLASS, //stored in the class file, but ignored by the VM
RUNTIME //stored in the class file and read by the VM
}
The default retention policy, for all annotations, is RetentionPolicy.CLASS
This retains annotations, but doesn’t require the VM to read them when classes are loaded
A good example of using Retention occurs in the SuppressWarnings annotation
As that annotation type is purely used for compilation – ensuring warning of the specified type are suppressed, it does not need to be retained in a class’s byte code
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
....
}
Documented
Annotations are not normally visible in the codes’ Javadoc
This is where the Documented meta-annotation comes into play
We can use it to ensure that our annotations show up in generated Javadoc
We need to add a @Documented meta-annotation to any annotation type that we want to appear in Javadoc
import java.lang.annotation.Documented;
import java.lang.annotation.Retention ;
import java.lang.annotation.RetentionPolicy ;
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface InProgress { }
Anytime we use the Documented annotation, we should pair it with a retention policy of RetentionPolicy.RUNTIME
Inherited
Annotations applied to super class are not automatically inherited by the sub-class
For example in the following code, InProgress annotation is not inherited by the sub-class Sub
@InProgress
public class Super {
....
}
public class Sub extends Super {
....
}
We need to used Inherited in the definition of the InProgress annotation type to fix this problem
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface InProgress { }
The above definition will make any sub-class of a class annotated with the InProgress annotation inherit the annotation
Annotations marked as Inherited only apply to sub-classes, so implementing a method with annotations will not result in the annotations being inherited
If we override a method from a super class, we don’t inherit that specific method’s annotations
Only the annotations on the super class itself are inherited, and those and those by the sub-class as a whole
No comments:
Post a Comment