Annotations

  • Annotations are the supplemental information to a source file which leaves the semantics of a program unchanged.
  • This information is used by various tools in both development and deployment.
  • Example this can be generated automatically by source code generator.
  • This is also called as Metadata.

Annotation Basics

  • An Annotation created based on the mechanism of interface as follows
//simple annotation type
@interface MyAnnotation
{
String str();
int val();
}
  • The interface keyword followed by @ represents it is Annotation.

  • No need to define the body of the code the class will implement the methods which are declared in Annotation.

  • We can't extend an Annotation but it implicitly extends the Annotation interface from java.lang.annotaion; package

  • We can annotate classes, methods, fields, parameters, and enum constants even an annotation can be annotated.

When we applying annotation we can assign it's values as follows

// Annotate a method.
@MyAnno(str = "Annotation Example", val = 100)  //str and val are the members of annotation where we are using them as fields in declaration
public static void myMeth() 
{ // ...

Specifying a Retention Policy

  • A retention policy determines at what point an annotation is discarded.
  • They are SOURCE, CLASS,and RUNTIME which are encapsulated within the java.lang.annotation.RetentionPolicy enumeration.

  • SOURCE-Available in source file but not in compilation.

  • CLASS-Available in class file means for compilation but not in JVM runtime.

  • RUNTIME-Available in source file, compilation and JVM runtime.

@Retention(retention-policy) //Retention is a java built in annotation to specify retention policy
@interface MyAnno
{
 String str();
 int val();
}

Use of Reflection

  • Although annotations are using by development and deployment tools,if they specify as RUNTIME then they can be accessed by other java programs by using Reflection.
  • Reflection is the feature that enables information about a class to be obtained at run time.
  • The reflection API is contained in the java.lang.reflect package.

Steps to use Reflection are:

  • We have to get the class object which represents the class whose annotations we want to use by using getClass() method in java.lang package.

final Class<?> getClass( ) //to get class object

  • By using this object we can get the information about methods, constructors etc as getMethod(), getFields(), getConstructor().

Method getMethod(String methName, Class ... paramTypes) // to get a method specified in methName, if there are arguments to method then they are specified by Class paramTypes which are varargs.

  • We can get an annotation with the following method

getAnnotation(Class annoType) //annotation type is the type of the annotation which we want to use which returns the refernece of the method where we can get the members of annotation otherwise it returnsnull means not in RUNTME.

//example for using reflection in annotations
import java.lang.annotation.*;
import java.lang.reflect.*;

// An annotation type declaration.
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnno
{
String str();
int val();
}

public class Simple
{
// Annotate a method.

@MyAnno(str = "Annotation Example", val = 100)
public static void myMeth()
{
Simple ob = new Simple();
// Obtain the annotation for this method
// and display the values of the members.

try
{
// First, get a Class object that represents this class.
Class<?> c = ob.getClass();
// Now, get a Method object that represents this method.
Method m = c.getMethod("myMeth");
// Next, get the annotation for this class.
MyAnno anno = m.getAnnotation(MyAnno.class);
// Finally, display the values.
System.out.println(anno.str() + " " + anno.val());
}
catch (NoSuchMethodException exc)
{
System.out.println("Method Not Found.");
}
}
public static void main(String args[])
{
myMeth();
}

Output:

Annotation Example 100

//example for a=g method having aruguments which is annotated.
import java.lang.annotation.*;
import java.lang.reflect.*;
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnno 

 String str();
 int val();
}
public class Meta
 {
 // myMeth now has two arguments.
 @MyAnno(str = "Two Parameters", val = 19)
 public static void myMeth(String str, int i)
 {
 Meta ob = new Meta();
 try 
 {
 Class<?> c = ob.getClass();
 // Here, the parameter types are specified.
 Method m = c.getMethod("myMeth", String.class, int.class);
 MyAnno anno = m.getAnnotation(MyAnno.class);
 System.out.println(anno.str() + " " + anno.val());
 } 
 catch (NoSuchMethodException exc) 
 {
 System.out.println("Method Not Found.");
 }
 }
 public static void main(String args[]) {
 myMeth("test", 10);
 }
}

Output:

Two Parameters 19

Obtaining All Annotations

We can obtain all annotations by the following method which returns the array of annotations.

Annotation[ ] getAnnotations( )

// Show all annotations for a class and a method.
import java.lang.annotation.*;
import java.lang.reflect.*;

@Retention(RetentionPolicy.RUNTIME)
@interface MyAnno
 {
 String str();
 int val();
}
@Retention(RetentionPolicy.RUNTIME)
@interface What 
{
 String description();
}

//annotating class
@What(description = "An annotation test class")
@MyAnno(str = "Meta2", val = 99)

public class Simple
{
 //annotating method
@What(description = "An annotation test method")
 @MyAnno(str = "Testing", val = 100)
 public static void myMeth() 
{
Simple ob = new Simple();
 try
 {
 Annotation annos[] = ob.getClass().getAnnotations();

 // Display all annotations for Meta2.
 System.out.println("All annotations for class Simple:");
 for(Annotation a : annos)
 System.out.println(a);
 System.out.println();

// Display all annotations for myMeth.
Method m = ob.getClass( ).getMethod("myMeth");
 annos = m.getAnnotations();
 System.out.println("All annotations for myMeth:");
 for(Annotation a : annos)
 System.out.println(a);
 } 
catch (NoSuchMethodException exc) 
{
 System.out.println("Method Not Found.");
 }
 }
 public static void main(String args[]) 
{
 myMeth();
 }
}

Output:

All annotations for class Simple:

@What(description=An annotation test class)

@MyAnno(str=Meta2, val=99)

All annotations for myMeth:

@What(description=An annotation test method)

@MyAnno(str=Testing, val=100)

The AnnotatedElement Interface

The methods getAnnotation() and getAnnotations() are defined from AnnotatedElement interface, which is defined in java.lang.reflect which also defines the methods like getDeclaredAnnotations( ) and isAnnotationPresent( ).

Annotation[ ] getDeclaredAnnotations( )- returns all non-inherited annotations present in the invoking object.

boolean isAnnotationPresent(Class annoType)-It returns true if the annotation specified by annoType is associated with the invoking object. It returns false otherwise.

Using Default Values

we can give default values to the members of annotation which will be used when if there is no assignment of values to those members this can be done by using default clause followed by member as follows.

type member( ) default value;

//example for using  default values for annotation members
import java.lang.annotation.*;
import java.lang.reflect.*;

// An annotation type declaration that includes defaults.
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnno 
{
 String str() default "Testing";
 int val() default 9000;
}

public class Simple 
{
 // Annotate a method using the default values.
 //@MyAnno() //all default values
@MyAnno(str = "some string") // val defaults
//@MyAnno(val = 100) //str defaults
//@MyAnno(str = "Testing", val = 100) // no defaults
 public static void myMeth() 
{
Simple ob = new Simple();
 // Obtain the annotation for this method
 // and display the values of the members.
 try 
{
 Class<?> c = ob.getClass();
Method m = c.getMethod("myMeth");
 MyAnno anno = m.getAnnotation(MyAnno.class);
 System.out.println(anno.str() + " " + anno.val());
 } 
 catch (NoSuchMethodException exc) 
 {
 System.out.println("Method Not Found.");
 }
 }

 public static void main(String args[]) 
 {
 myMeth();
 }
}

Output:

some string 9000

Marker Annotations

  • A marker annotation is a special kind of annotation that contains no members.
  • Its role purpose is to mark an item. Thus, its presence as an annotation is sufficient.
  • The best way to determine if a marker annotation is presence is to use the method isAnnotationPresent( ).
//example for marker annotation
import java.lang.annotation.*;
import java.lang.reflect.*;

// A marker annotation.
@Retention(RetentionPolicy.RUNTIME)
@interface MyMarker { }

public class Simple
 {
 // Annotate a method using a marker.
 // Notice that no ( ) is needed.
 @MyMarker
 public static void myMeth() 
{
Simple ob = new Simple();
 try 
{
 Method m = ob.getClass().getMethod("myMeth");

// Determine if the annotation is present.
 if(m.isAnnotationPresent(MyMarker.class))
 System.out.println("MyMarker is present.");
 }

catch (NoSuchMethodException exc) 
{
 System.out.println("Method Not Found.");
 }
 }
public static void main(String args[]) 
{
 myMeth();
 }
}

Output:

MyMarker is present.

Single-Member Annotations

  • A single-member annotation contains only one member.
  • It is just like a normal annotation but specifies the shorthand form to assign value to the member by specifying the value no need of name of the member as follows

@MySingle(100)

  • Here the name of the member should be valueas follows

@interface MySingle

{

int value(); // this variable name must be value

}

//example for single member annotations
import java.lang.annotation.*;
import java.lang.reflect.*;

// A single-member annotation.
@Retention(RetentionPolicy.RUNTIME)
@interface MySingle 
{
 int value(); // this variable name must be value if we use val() it will shows error
}

public class Simple 
{
 // Annotate a method using a single-member annotation.
 @MySingle(100)
 public static void myMeth() 
{
 Simple ob = new Simple();
 try 
{
 Method m = ob.getClass().getMethod("myMeth");
 MySingle anno = m.getAnnotation(MySingle.class);
 System.out.println(anno.value()); // displays 100
 } 
catch (NoSuchMethodException exc) 
{
 System.out.println("Method Not Found.");
 }
 }
public static void main(String args[])
 {
 myMeth();
 }
}

Output:

100

//example for using single member annotation if there is more than one members
import java.lang.annotation.*;
import java.lang.reflect.*;

// A single-member annotation.
@Retention(RetentionPolicy.RUNTIME)
@interface MySingle 
{
 int value(); // this variable name must be value
int xyz() default 0; //we have to use default value as we are using single member annotation as @MySingle(100)

//if want to use both then we have to use like @MySingle(value=100, xyz=98)
}

public class Simple 
{
 // Annotate a method using a single-member annotation.
 @MySingle(100)
 public static void myMeth() 
{
 Simple ob = new Simple();
 try 
{
 Method m = ob.getClass().getMethod("myMeth");
 MySingle anno = m.getAnnotation(MySingle.class);
 System.out.println(anno.value()); // displays 100
System.out.println(anno.xyz()); // default value 0
 } 
catch (NoSuchMethodException exc) 
{
 System.out.println("Method Not Found.");
 }
 }
public static void main(String args[])
 {
 myMeth();
 }
}

Output:

100

0

The Built-In Annotations

  • Java defines many built-in annotations.

  • But nine are general purpose annotations.

  • @Retention, @Documented, @Target, and @Inherited these four are imported from java.lang.annotation.

  • @Override, @Deprecated, @FunctionalInterface, @SafeVarargs, and @SuppressWarnings are included in java.lang.

@Retention

It is designed to be used only as an annotation to another annotation.

@Documented

  • The @Documented annotation is a marker interface that tells a tool that an annotation is to be documented.
  • It is designed to be used only as an annotation to an annotation declaration.

@Target

  • It specifies the types of items to which an annotation can be applied.
  • It is designed to be used only as an annotation to another annotation.

  • It takes one argument, which is an array of constants of the ElementType enumeration.

  • This argument specifies the types of declarations to which the annotation can be applied.

Target Constant Annotation Can be Applied To
ANNOTATION_TYPE Another annotation.
CONSTRUCTOR Constructor.
FIELD Field
LOCAL_VARIABLE Local Variable.
METHOD Method.
PACKAGE Package.
PARAMETER Parameter.
TYPE Class, interface or enumeration.
TYPE_PARAMETER Type parameter (in JDK8).
TYPE_USE Type Use(in JDK8).

We can use these constants as follows

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

@Inherited

  • @Inherited is a marker annotation that can be used only on another annotation declaration.

  • It causes the annotation for a superclass to be inherited by a subclass.

  • when a request for a specific annotation is made to the subclass,if that annotation is not present in the subclass, then its superclass is checked.

  • If that annotation is present in the superclass, and if it is annotated with @Inherited, then that annotation will be returned.

@Override

  • @Override is a marker annotation that can be used only on methods.

  • A method annotated with @Override must override a method from a superclass.

  • If it doesn’t, a compile-time error will result.

  • It is for overriding by superclass and not simply overloading.

@Deprecated

  • @Deprecated is a marker annotation.
  • It indicates that a declaration is obsolete and has been replaced by a newer form.

@FunctionalInterface

  • @FunctionalInterface is a marker annotation added by JDK 8 and designed for use on interfaces.
  • It indicates that the annotated interface is a functional interface.

  • It is interface which contains one and only one abstract method.

  • Otherwise compilation error will be reported.

  • It is not needed to create a functional interface. Any interface with exactly one abstract method is, by definition, a functional interface.Thus, @FunctionalInterface is purely informational.

@SafeVarargs

  • @SafeVarargs is a marker annotation that can be applied to methods and constructors.
  • It indicates that no unsafe actions related to a varargs parameter occur.

  • It must be applied only to vararg methods or constructors that are static or final.

@SuppressWarnings

  • It specifies that one or more warnings that might be issued by the compiler are to be suppressed.

  • The warnings to suppress are specified by name, in string form.

Type Annotations

  • In JDK 8, annotations can also be specified in most cases in which a type is used.
  • This expanded aspect of annotations is called type annotation.

  • we can annotate the return type of a method, the type of this within a method, a cast,array levels, an inherited class, and a throws clause.

  • we can also annotate generic types, including generic type parameter bounds and generic type arguments.

  • These are important because they enable tools to perform additional checks on code to help prevent errors.

  • A type annotation must include ElementType. TYPE_USE as a target.

void myMeth() throws @TypeAnno NullPointerException { // ...

  • Here @TypeAnno annotates NullPointerException in the throws clause.

  • we can also annotate the type of this.

    class SomeClass

{

int myMeth(SomeClass this, int i, int j)

{ // ...

Here myMeth( ) is a method defined by SomeClass, the type of this is SomeClass.

int myMeth(@TypeAnno SomeClass this, int i, int j)

'{ // ...

  • it is not necessary to declare this unless you are annotating it.

  • this will be used only if you want to apply a type annotation to it.

  • If we declare this, it must be the first parameter.

// Demonstrate several type annotations.
import java.lang.annotation.*;
import java.lang.reflect.*;

// A marker annotation that can be applied to a type.
@Target(ElementType.TYPE_USE)
@interface TypeAnno 
{
 }

// Another marker annotation that can be applied to a type.
@Target(ElementType.TYPE_USE)
@interface NotZeroLen 
{
}

// Still another marker annotation that can be applied to a type.
@Target(ElementType.TYPE_USE)
@interface Unique 
{ 
}

// A parameterized annotation that can be applied to a type.
@Target(ElementType.TYPE_USE)
@interface MaxLen
 {
 int value();
}

// An annotation that can be applied to a type parameter.
@Target(ElementType.TYPE_PARAMETER)
@interface What
 {
 String description();
}

// An annotation that can be applied to a field declaration.
@Target(ElementType.FIELD)
@interface EmptyOK 
{
 }

// An annotation that can be applied to a method declaration.
@Target(ElementType.METHOD)
@interface Recommended 
{ 
}

// Use an annotation on a type parameter.
public class Simple<@What(description = "Generic data type") T>
 {
 // Use a type annotation on a constructor.

 public @Unique Simple()
 {
}

// Annotate the type (in this case String), not the field.
 @TypeAnno String str;

 // This annotates the field test.
 @EmptyOK String test;
// Demonstrate several type annotations.
import java.lang.annotation.*;
import java.lang.reflect.*;

// A marker annotation that can be applied to a type.
@Target(ElementType.TYPE_USE)
@interface TypeAnno 
{
 }

// Another marker annotation that can be applied to a type.
@Target(ElementType.TYPE_USE)
@interface NotZeroLen 
{
}

// Still another marker annotation that can be applied to a type.
@Target(ElementType.TYPE_USE)
@interface Unique 
{ 
}

// A parameterized annotation that can be applied to a type.
@Target(ElementType.TYPE_USE)
@interface MaxLen
 {
 int value();
}

// An annotation that can be applied to a type parameter.
@Target(ElementType.TYPE_PARAMETER)
@interface What
 {
 String description();
}

// An annotation that can be applied to a field declaration.
@Target(ElementType.FIELD)
@interface EmptyOK 
{
 }

// An annotation that can be applied to a method declaration.
@Target(ElementType.METHOD)
@interface Recommended 
{ 
}

// Use an annotation on a type parameter.
public class Simple<@What(description = "Generic data type") T>
 {
 // Use a type annotation on a constructor.

 public @Unique Simple()
 {
}

// Annotate the type (in this case String), not the field.
 @TypeAnno String str;

 // This annotates the field test.
 @EmptyOK String test;

 // Use a type annotation to annotate this (the receiver).
 public int f(@TypeAnno Simple<T> this, int x)
 {
 return 10;
 }
 // Annotate the return type.
 public @TypeAnno Integer f2(int j, int k) 
{
 return j+k;
 }
 // Annotate the method declaration.
 public @Recommended Integer f3(String str)
 {
 return str.length() / 2;
 }
 // Use a type annotation with a throws clause.
 public void f4() throws @TypeAnno NullPointerException
 {
 // ...
 }

 // Annotate array levels.
 String @MaxLen(10) [] @NotZeroLen [] w;

 // Annotate the array element type.
 @TypeAnno Integer[] vec;
 public static void myMeth(int i)
 {

// Use a type annotation on a type argument.
Simple<@TypeAnno Integer> ob = new Simple<@TypeAnno Integer>();
 // Use a type annotation with new.
 @Unique Simple<Integer> ob2 = new @Unique Simple<Integer>();
 Object x = new Integer(10);
 Integer y;
 // Use a type annotation on a cast.
 y = (@TypeAnno Integer) x;
 }
 public static void main(String args[]) {
 myMeth(10);
 }
 // Use type annotation with inheritance clause.
 class SomeClass extends @TypeAnno Simple<Boolean> {}
}
 // Use a type annotation to annotate this (the receiver).
 public int f(@TypeAnno Simple<T> this, int x)
 {
 return 10;
 }
 // Annotate the return type.
 public @TypeAnno Integer f2(int j, int k) 
{
 return j+k;
 }
 // Annotate the method declaration.
 public @Recommended Integer f3(String str)
 {
 return str.length() / 2;
 }
 // Use a type annotation with a throws clause.
 public void f4() throws @TypeAnno NullPointerException
 {
 // ...
 }

 // Annotate array levels.
 String @MaxLen(10) [] @NotZeroLen [] w;

 // Annotate the array element type.
 @TypeAnno Integer[] vec;
 public static void myMeth(int i)
 {

// Use a type annotation on a type argument.
Simple<@TypeAnno Integer> ob = new Simple<@TypeAnno Integer>();
 // Use a type annotation with new.
 @Unique Simple<Integer> ob2 = new @Unique Simple<Integer>();
 Object x = new Integer(10);
 Integer y;
 // Use a type annotation on a cast.
 y = (@TypeAnno Integer) x;
 }
 public static void main(String args[]) {
 myMeth(10);
 }
 // Use type annotation with inheritance clause.
 class SomeClass extends @TypeAnno Simple<Boolean> {}
}

Repeating Annotations

  • JDK 8 annotation feature enables an annotation to be repeated on the same element. This is called Repeating annotations.
  • it must be annotated with the @Repeatable annotation, defined in java.lang.annotation.

  • For this we have to create a container annotation and then specify that annotation type as an argument to the @Repeatable annotation.

// Demonstrate a repeated annotation.
import java.lang.annotation.*;
import java.lang.reflect.*;

// Make MyAnno repeatable.
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(MyRepeatedAnnos.class) //MyRepeatedAnnos is the container annotaion
@interface MyAnno 
{
 String str() default "Testing";
 int val() default 9000;
}

// This is the container annotation.
@Retention(RetentionPolicy.RUNTIME)
@interface MyRepeatedAnnos 
{
 MyAnno[] value(); //specified as an annotation for which the value field is an array of the repeatable annotation type. 
}

public class Simple 
{

 // Repeat MyAnno on myMeth().
 @MyAnno(str = "First annotation", val = -1)
 @MyAnno(str = "Second annotation", val = 100)

public static void myMeth(String str, int i)
 {
 Simple ob = new Simple();
 try 
{
 Class<?> c = ob.getClass();

 // Obtain the annotations for myMeth().
 Method m = c.getMethod("myMeth", String.class, int.class);

 // Display the repeated MyAnno annotations.
 Annotation anno = m.getAnnotation(MyRepeatedAnnos.class);
 System.out.println(anno);
 } 
catch (NoSuchMethodException exc) 
{
 System.out.println("Method Not Found.");
 }
 }
 public static void main(String args[]) 
{
 myMeth("test", 10);
 }
}

Output:

@MyRepeatedAnnos(value=[@MyAnno(val=-1, str=First annotation), @MyAnno(val=100, str=Second annotation)])

  • Here annotations are separated by comma meas it is not displaying individually to achieve this we can use getAnnotationsByType( ) and getDeclaredAnnotationsByType( ) which are defined from AnnotatedElement by JDK 8.

T[ ] getAnnotationsByType(Class annoType)

  • It returns an array of the annotations of annoType associated with the invoking object.
// Demonstrate a repeated annotation using getAnnotationByType() using for-each loop.
import java.lang.annotation.*;
import java.lang.reflect.*;

// Make MyAnno repeatable.
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(MyRepeatedAnnos.class) //MyRepeatedAnnos is the container annotaion
@interface MyAnno 
{
 String str() default "Testing";
 int val() default 9000;
}

// This is the container annotation.
@Retention(RetentionPolicy.RUNTIME)
@interface MyRepeatedAnnos 
{
 MyAnno[] value(); //specified as an annotation for which the value field is an array of the //repeatable annotation type. 
}

public class Simple 
{

 // Repeat MyAnno on myMeth().
 @MyAnno(str = "First annotation", val = -1)
 @MyAnno(str = "Second annotation", val = 100)

public static void myMeth(String str, int i)
 {
 Simple ob = new Simple();
 try 
{
 Class<?> c = ob.getClass();

 // Obtain the annotations for myMeth().
 Method m = c.getMethod("myMeth", String.class, int.class);

 // Display the repeated MyAnno annotations.
 Annotation[] annos = m.getAnnotationsByType(MyAnno.class);

for(Annotation a : annos)
 System.out.println(a);
 } 
catch (NoSuchMethodException exc) 
{
 System.out.println("Method Not Found.");
 }
 }
 public static void main(String args[]) 
{
 myMeth("test", 10);
 }
}

Output:

@MyAnno(val=-1, str=First annotation)

@MyAnno(val=100, str=Second annotation)

Some Restrictions

To apply annotations there are some restrictions as follows

  • No annotation can inherit another.

  • All methods declared by an annotation must be without parameters.

  • Those methods return one of the following:

    • A primitive type, such as int or double

    • An object of type String or Class

• An enum type

• Another annotation type

• An array of one of the preceding types

  • Annotations cannot be generic means they cannot take type parameters.

  • annotation methods cannot specify a throws clause.

results matching ""

    No results matching ""