Class and Runtime Retention Policy
Annotations with Retention Policy CLASS and RUNTIME are accessible from class byte code.
We need to use a byte code manipulation library to access the Annotations available in byte code.
This example uses ASM to fetch Annotations from class byte code.
Annotations with Retention Policy CLASS,
package com.bethecoder.tutorials.annotations.retention2;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Permitted types for annotation attributes
*
* 1. primitive type
* 2. String
* 3. Class
* 4. annotation
* 5. enumeration
* 6. 1-dimensional arrays
*/
@Retention ( RetentionPolicy.CLASS )
@Target ( ElementType.TYPE )
public @interface Author {
String name () default "admin" ;
String creationDate () ;
}
Annotations with Retention Policy RUNTIME,
package com.bethecoder.tutorials.annotations.retention2;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Permitted types for annotation attributes
*
* 1. primitive type
* 2. String
* 3. Class
* 4. annotation
* 5. enumeration
* 6. 1-dimensional arrays
*/
@Retention ( RetentionPolicy.RUNTIME )
@Target ( ElementType.TYPE )
public @interface VersionHistory {
String [] value () ;
}
Its usage is shown below,
package com.bethecoder.tutorials.annotations.retention2;
@Author ( name= "BTC" , creationDate= "01/01/2500" )
@VersionHistory ({ "1.0" , "2.0" , "3.0" })
public class Source {
private int fieldOne;
private String fieldTwo;
public Source ( int fieldOne, String fieldTwo ) {
super () ;
this .fieldOne = fieldOne;
this .fieldTwo = fieldTwo;
}
public int getFieldOne () {
return fieldOne;
}
public void setFieldOne ( int fieldOne ) {
this .fieldOne = fieldOne;
}
public String getFieldTwo () {
return fieldTwo;
}
public void setFieldTwo ( String fieldTwo ) {
this .fieldTwo = fieldTwo;
}
}
The ASM Tree API code to access Annotations is shown below,
package com.bethecoder.tutorials.annotations.retention2;
import java.util.List;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.tree.AnnotationNode;
import org.objectweb.asm.tree.ClassNode;
public class Test {
/**
* @param args
*/
public static void main ( String [] args ) throws Exception {
//ASM Tree API
ClassNode cn = new ClassNode () ;
//Read the class byte code from stream
ClassReader cr = new ClassReader (
ClassLoader.getSystemResourceAsStream (
"com/bethecoder/tutorials/annotations/retention2/Source.class" )) ;
cr.accept ( cn, 0 ) ;
System.out.println ( "Class Name : " + cn.name ) ;
System.out.println ( "Source File : " + cn.sourceFile ) ;
//Annotations with RetentionPolicy.CLASS
//@Retention(RetentionPolicy.CLASS)
System.out.println ( "\n==Invisible Annotations==" ) ;
printAnnotation ( cn.invisibleAnnotations ) ;
//Annotations with RetentionPolicy.RUNTIME
//@Retention(RetentionPolicy.RUNTIME)
System.out.println ( "\n==Visible Annotations==" ) ;
printAnnotation ( cn.visibleAnnotations ) ;
}
private static void printAnnotation ( List annotationList ) {
if ( annotationList != null && !annotationList.isEmpty ()) {
AnnotationNode anNode = null ;
for ( Object annotation : annotationList ) {
anNode = ( AnnotationNode ) annotation;
System.out.println ( "Annotation Descriptor : " + anNode.desc ) ;
System.out.println ( "Annotation attribute pairs : " + anNode.values ) ;
}
} else {
System.out.println ( "No annotations found.." ) ;
}
}
}
It gives the following output,
Class Name : com/bethecoder/tutorials/annotations/retention2/Source
Source File : Source.java
==Invisible Annotations==
Annotation Descriptor : Lcom/bethecoder/tutorials/annotations/retention2/Author;
Annotation attribute pairs : [name, BTC, creationDate, 01/01/2500]
==Visible Annotations==
Annotation Descriptor : Lcom/bethecoder/tutorials/annotations/retention2/VersionHistory;
Annotation attribute pairs : [value, [1.0, 2.0, 3.0]]