Tuesday, December 23, 2008

Meta Annotations

­          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: