Java Annotations

Java supported a feature that enables you to embed the supplemental information into a source file. This information, known an annotation that doesn't change the actions of a program. Thus, a annotation leaves the semantics of a program unchanged. Nevertheless, this information can be used by various tools during both development and deployment. For example, an annotation may be processed by a source-code generator.

Java Metadata

In Java, the term metadata is also used to refer to this feature, but the term annotation is the most descriptive and more commonly used.

Create Annotation in Java

An annotation can be created through a mechanism based on the interface. Let's start with an example. Following is the declaration for an annotation called MyAnnotat :

/* a simple annotation type */
@interface MyAnnotat
{
   String str();
   int val();
}

First notice here, the @ that precedes the keyword interface. This tells the compiler that an annotation type is being declared. Next, notice at the two members, str() and val(). All annotations consist solely of method declarations. Nevertheless, you do not provide bodies for these methods. Instead, Java implements these methods. Moreover, the methods act much like the fields.

An annotation can't include the extends clause. However, all the annotation types automatically extend the Annotation interface. Hence, Annotation is a super-interface of all the annotations. It is declared within java.lang.annotation package. It overrides the methods hashCode(), equals(), and toString() which are defined by Object. It also specifies a method annotationType(), returns a Class object that represents the invoking annotation.

When you have declared an annotation, you can use it to annotate something.

Any type of declaration can have an annotation linked with it. For example, classes, methods, parameters, fields, and enum constants can be annotated. Even an annotation can be annotated. In all the cases, the annotation precedes the rest of the declaration.

When you apply an annotation, means you are giving values to its members. For example, following is an example of MyAnnotat being applied to a method declaration:

/* annotate a method */
@MyAnnotat(str = "Annotation Example", val = 10)
public static void myMethod() { // ...

This annotation is linked with the method named myMethod(). Look closely at the annotation syntax. The name of the annotation, preceded by @, is followed by a parenthesized list of member initializations. To give a member a value, that member's name is assigned a value. Therefore, in the example, the string "Annotation Example" is assigned to the str member of MyAnnotat.

Notice that no parentheses come after the str in this assignment. When an annotation member is given a value, only its name is used. Hence, annotation members look like fields in this context.

Specify Retention Policy in Java

It is necessary to discuss the annotation retention policies before exploring annotation further.

A retention policy determines that, at what point an annotation is discarded.

Java defines three such policies, which are encapsulated within java.lang.annotation.RetentionPolicy enumeration. They are:

Note - An annotation on a local variable declaration is not retained in the .class file

A retention policy is specified for an annotation by using one of the Java's built-in annotations: @Retention. Its general form is shown below :

@Retention(retention-policy)

Here, retention-policy must be one of previously discussed enumeration constants. If no retention policy is specified for an annotation, then the default policy of the CLASS is used.

The following version of MyAnnotat uses the @Retention to specify the RUNTIME retention policy. Hence, MyAnnotat will be available to the JVM during program execution.

@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotat {
   String str();
   int val();
}

Get Annotations at Run Time in Java

Even though annotation are designed mostly for use by other development or deployment tools, if they specify a retention policy of RUNTIME, then they can be queried at the run time by any Java program through the use of reflection.

Reflection is the feature that enables the information about a class to be obtained at run time.

The reflection API is contained in java.lang.reflect package. There are a number of ways to use reflection, and we won't examine them all here. We will walk through a few examples that apply to annotations.

The first step to using the reflection is to obtain a Class object which represents the class whose annotations you want to obtain.

Class is one of Java's built-in classes and is defined in java.lang package.

There are various ways to obtain a Class object. One of the easiest way is to call the getClass() method, defined by Object. Its general form is shown below :

final Class<?> getClass()

It returns Class object that represents the invoking object.

After you have obtained a Class object, you can use its methods to obtain the information about the various items declared by the class, including its annotations. If you want to obtain all the annotations associated with a specific item declared within a class, you must first obtain an object which represents that item. For example, Class supplies (among others) the getMethod(), getField(), and getConstructor() methods, which obtain the information about a method, field, and constructor, respectively. These methods return objects of type Method, Field, and Constructor.

To understand the process, let us work through an example that obtains the annotations associated with a method. To do this, you first obtain a Class object which represent the class, and then call the getMethod() on that Class object, specifying the name of method. getMethod() has the following general form ::

Method getMethod(String methName, Class<?> ... paramTypes)

The name of the method is passed in the methName. If the method has arguments, then Class objects representing those types must also be specified by paramTypes. Notice here that, paramTypes is a varargs parameter. This means that you can specify as many parameter types as required, including zero. The getMethod() returns a Method object that represents the method. If the method can't be found, NoSuchMethodException is thrown.

From a Class, Method, Field, or a Constructor object, you can obtain a specific annotation associated with that object by calling the method getAnnotation(). Its general form is shown below :

<A extends Annotation> getAnnotation(Class<A> annoType)

Here, the annoType is a Class object that represents the annotation in which you are interested. The method returns a reference to annotation. Using this reference, you can get the values associated with the annotation's members. The method returns null, in case if the annotation is not found, that will be the case if the annotation doesn't have RUNTIME retention.

Java Annotation Example

Following is an example program that assembles all of the pieces shown earlier and uses reflection to display the annotation associated with a method:

/* Java Program Example - Java Annotations (Metadata) */

import java.lang.annotation.*;
import java.lang.reflect.*;

/* an annotation type declaration */
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotat {
   String str();
   int val();
}

class Meta {
   
   /* annotate a method */
   @MyAnnotat(str = "Annotation Example", val = 10)
   
   public static void myMethod() {
      Meta obj = new Meta();
      
      /* 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 = obj.getClass();
        
        /* now, get a method object that 
        *  represents this method */
        Method m = c.getMethod("myMethod");
        
        /* next, get the annotation for this class */
        MyAnnotat anno = m.getAnnotation(MyAnnotat.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[]) {
   
      myMethod();
      
   }
}

The output of this program is:

Annotation Example l0

This program uses reflection as described to get and display the values of str and val in MyAnnotat annotation associated with the method named myMethod() in the Meta class. There are two things to pay special attention. First, in this line

MyAnnotat anno = m.getAnnotation(MyAnnotat.class);

notice the expression MyAnnotat.class which evaluates to a Class object of the type MyAnnotat, the annotation. This concept is called a class literal. You can use this type of expression whenever a Class object of a known class is needed. For example, the below statement could have been used to get the Class object for the Meta :

Class<?> c = Meta.class;

Of course, this approach only works when you know the class name of an object in advance, which might not always be the case. In general, you can get a class literal for classes, interfaces, primitive types, and arrays.

Note - The syntax <?> relates to the generic feature of Java.

The second point of interest is the way the values associated with str and val are got when they are output by the following lines:

System.out.println(anno.str() + " " + anno.val());

Notice here that they are invoked using the method-call syntax. This same approach is used whenever the value of an annotation member is required.

Get All Annotations in Java

You can get all annotations that have RUNTIME retention that are associated with an item by calling getAnnotations() on that item. It has the following general form :

Annotation[] getAnnotations()

It returns an array of the annotations. The method getAnnotations() can be called an objects of type Class, Method, Constructor, and Field, among the others.

Following is reflection example that shows how to obtain all annotations associated with a class and with a method. This declares two annotations. It then uses those annotations to annotate a class and a method.

/* Java Program Example - Java Annotations (Metadata)
*  Show all annotations for a class and a method */

import java.lang.annotation.*;
import java.lang.reflect.*;

@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotat {
   String str();
   int val();
}

@Retention(RetentionPolicy.RUNTIME)
@interface What {
   String description();
}

@What(description = "An annotation test class")
@MyAnnotat(str = "Meta", val = 9)
class Meta {

   @What(description = "An annotation test method")
   @MyAnnotat(str = "Testing", val = 10)
   public static void myMethod() {
      Meta obj = new Meta();
     
     try {
        Annotation annos[] = obj.getClass().getAnnotations();
       
       /* display all annotations for Meta */
       System.out.println("All annotations for Meta : ");
       for(Annotation a : annos)
          System.out.println(a);
         
       System.out.println();
       
       /* display all annotations for myMethod */
       Method m = obj.getClass().getMethod("myMethod");
       annos = m.getAnnotations();
       
       System.out.println("All annotations for myMethod : ");
       for(Annotation a : annos)
          System.out.println(a);
         
     } catch(NoSuchMethodException exc) {
        System.out.println("Method not Found");
      }
   }
   
   public static void main(String args[])
   {
      myMethod();
   }
}

The output of the above Java program is :

All annotations for Meta :
@What(description = An annotation test class)
@MyAnnotat(str = Meta, val = 9)

All annotations for myMethod :
@What(description = An annotation test method)
@MyAnnotat(str = Testing, val = 10)

The program uses the getAnnotations() to obtain an array of all the annotations associated with Meta class and with myMethod() method. As explained, the getAnnotations() returns an array of Annotation objects. Recall that Annotation is a super-interface of all the annotation interfaces and that it overrides toString() in Object. Thus, when a reference to an Annotation is output, its method toString() is called to generate string that describes the annotation, as the preceding output shows.

Java Online Test


« Previous Tutorial Next Tutorial »