Annotations in Java | Meta Annotations, Example

An annotation in Java is a kind of note (or documentation) in the application source code to instruct the Java compiler to do something.

When the Java compiler sees annotation in a particular source code, it knows that it needs to do something special with the code that follows.

We can annotate Java packages, classes, interfaces, constructors, methods, fields, local variables, and parameters.

For example, we can annotate a method that we want to override to tell the Java compiler for verifying that we are really overriding the method, not overloading it.

Java annotations are helpful in providing a systematic way to add extra information for a particular code in a functional way that is understood, tested, and verified by Java compiler and JVM.

Annotations are an incredibly powerful new feature that was first added to Java 5.

Java provides some predefined annotations, but we can also easily create custom (user-defined) annotations that can be used with our application code to provide some special functionality.

In this tutorial, we will concentrate on predefined annotations provided by Java language, and in the next tutorial, we will learn user-defined annotations.

Java Annotations Syntax


An annotation acts like a tag that is used to provide metadata for java source code. Metadata is data that provides a piece of information about other data.

Annotations in Java always start with @ symbol and must be placed directly before the code being annotated. The general syntax to declare an annotation is as follows:

@AnnotationType
Or,
@AnnotationType(elementValuePairs)

The first syntax is used to declare marker annotation types. For example, @Deprecated is a marker annotation type.

The second syntax is used to declare single value or multi-value types. For example:

@Person(firstName = "Ivaan", lastName = "Sagar")
@Stage(value = 1)
@Stage(1)

Standard Built-in Annotations (Predefined annotations) in Java


Java 5 contains three general-purpose commonly standard built-in annotations, defined in java.lang.annotation package that is used to give instructions to the Java compiler. They are as follows:

  1. @Deprecated
  2. @Override
  3. @SuppressWarnings

Later on, Java 7 and Java 8 added SafeVarargs and FunctionalInterface annotations in the java.lang.annotation package.

Let’s understand them one by one with examples.

Deprecated Annotation


The @Deprecated annotation is a type of marker annotation that can be used to mark a class, method, field, or other programming features as deprecated, meaning it should be no longer in use.

If your source code uses a deprecated class, method, or field in a program, Java compiler will produce a warning message for you at compile time.

This message informs the programmer that it was available in earlier versions of JDK but will be no more available in the coming versions or in the current version. So, it may work today, but there is no guarantee that it will keep working forever.


When it happens, we need to update their code and stop using that particular class, method, field, or other programming features.

Let’s take a simple example program where we will mark a method as deprecated.

Program source code 1:

public class DeprecatedTest
{
public void x() {
       System.out.println("Hello x");	
}
@Deprecated	
 public void y() 
 {
      System.out.println("Hello y");	 
 }
public static void main(String[] args) {
DeprecatedTest obj = new DeprecatedTest();
   obj.x();
   obj.y();
 }
}
Output:
          Hello x
          Hello y

We can use @Deprecated annotation to mark a class or interface on the top. Here is an example of a class that is marked as deprecated.

@Deprecated
public class DeprecatedClass
{
   void x() {
  
    }
}

@Override Annotation


The @Override annotation is a type of marker annotation that is used above a method to indicate to the Java compiler that the subclass method is overriding the superclass method.

If this annotation is present above a method and the method signature does not match a method signature in the superclass, the compiler will produce an error so that we could know something is wrong with the override.

The @Override annotation is not essential to override a method in the superclass. In case someone changed the name of the overridden method in the superclass, or did a spelling mistake then the subclass method would no longer override it.

In this situation, without @Override annotation, we would not find out. Therefore, it is better to mark a method with @Override annotation that provides assures the programmer that this method is overridden.

With @Override annotation, Java compiler would indicate to you that subclass method is not overriding superclass method.


Let’s take a simple example program based on the @Override annotation in Java.

Program source code 2:

public class A
{
void m1() {
       System.out.println("A-m1");	
 }
}
public class B extends A 
{
 void m1(int a)
 {
      System.out.println("B-m1"); 
 }
public static void main(String[] args) {
B b = new B();
   b.m1(20);
 }
}
Output:
           B-m1

In this program, m1() method in subclass is not overriding the method present in the superclass because it has a different method signature. Using @Override annotation, we can avoid this kind of mistake. Let’s see in the below code.

Program source code 3:

public class A
{
void m1() {
     System.out.println("A-m1");	
 }
}
public class B extends A 
{
@Override	
 void m1(int a)
 {
     System.out.println("B-m1"); 
 }
public static void main(String[] args) {
B b = new B();
   b.m1(20);
 }
}
Output:
        Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
	The method m1(int) of type B must override or implement a supertype method

This time, Java compiler will produce a compile-time error and you will observe that m1() method in subclass is not overriding the method in superclass.

So, it is clear that whenever you want to override a method, mark the method with @Override annotation.

@Suppress Warnings Annotation


The @SuppressWarnings annotation is used to suppress warnings generated by the compiler. In other words, this annotation is used to turn off inappropriate compiler warnings.

For example, if a method calls a deprecated method, or makes an insecure type cast, the compiler may generate a warning message about it.

We can suppress this warnings message by annotating the method containing the code with @SuppressWarnings annotation.

This @SuppressWarnings annotation can be applied with types, constructors, methods, fields, parameters, and local variables.

Let’s take a simple example program based on the Java @SuppressWarnings annotation.

Program source code 4:

import java.util.ArrayList;
public class SupressWarningsTest  
{
@SuppressWarnings({ "unchecked", "rawtypes" })	
public static void main(String[] args) {
ArrayList arList = new ArrayList();
  arList.add("Orange");
  arList.add("Pink");
  arList.add("Red");
  arList.add("Green");
  arList.add("Blue");
 
 for(Object obj : arList) {
	System.out.println(obj); 
   }
 }
}
Output:
          Orange
          Pink
          Red
          Green
          Blue

As you can notice that no warning at the compile time. If you remove @SuppressWarnings({ “unchecked”, “rawtypes” }) annotation, it will show a warning at the compile-time because we are using a non-generic collection.

@FunctionalInterface Annotation


A functional interface in java is an interface in which we can declare only one abstract method.

The @FunctionalInterface is a marker annotation type that is used to verify compiler that interface has one and only abstract method.

If an interface is not annotated with this annotation is not functional interface, the compiler will generate a compile-time error. It cannot be used with classes, annotation types, and enums.

Let’s take a simple example where an interface Person uses a @FunctionalInterface annotation.

@FunctionalInterface
public interface Person {
         void play(); // Only one abstract method.
}

The following declaration of Student interface uses a @FunctionalInterface annotation that will generate compile-time error because Student interface defines two abstract methods and therefore, it is not a functional interface.

@FunctionalInterface
public interface Student 
{
    void play();
    void read();
}

Note: If an interface has only one abstract method, it is always a functional interface whether it is annotated with @FunctionalInterface or not.

@SafeVarargs Annotation


When we use @SafeVarargs annotation with method or constructor, method or constructor does not perform potentially unsafe or harmful operations on its varargs parameters.

When this annotation is used with method or constructor, unchecked warnings relating to varargs usage are suppressed.

Standard Meta Annotations in Java


Annotations that are used to annotate annotations are called meta annotations in java. In other simple words, annotations that are applied to other annotations are called meta-annotations.

There are four types of meta-annotations that can be used to annotate annotations. They are as follows:

  1. Documented
  2. Inherited
  3. Retention
  4. Target
  5. Repeatable
  6. Native

All these four meta-annotations are declared in the java.lang.annotation package. Let’s concentrate on these four meta annotations.

@Documented Annotation


The @Documented is a type of marker meta annotation that is used to annotate the declaration of an annotation type.

If an annotation type is declared with @Documented annotation then the Javadoc tool will generate documentation for all of its instances of annotation type.

For example, @Override annotation cannot be annotated with @Documented annotation. If we generate documentation by using Javadoc tool for a class Test whose method is annotated with @Override, we will not see any mark of @Override in the resulting documentation.

Let’s take a simple example. In the below code, Test class uses @Override annotation to annotate the toString method.

package annotationProgram;
public class Test
{
  @Override
  public String toString()
  {
        return "Test";
   }
}

On the other hand, @Deprecated annotation type can be annotated with @Documented annotation. In the above program source code 1, y() method in class DeprecatedTest is annotated with @Deprecated.

Now, if we use Javadoc tool to generate the documentation for class DeprecatedTest, the details of y() method in the documentation will also include @Deprecated, like this:

y
@Deprecated
public void y()

@Inherited Annotation


The @Inherited annotation is a type of meta marker annotation that is used to inherit an instance of annotation type.

For example, if we annotate a class using an Inherited meta-annotation, the annotation will be inherited by any subclass of the annotated class.

It has no effect if we try to annotate any class’s members other than a class declaration. Let’s consider two annotation type declarations: Test1 and Test2.

Here, Test1 is not annotated with an Inherited meta-annotation, whereas Test3 is annotated with an Inherited meta-annotation.

public @interface Test1 {
     int id();
}
@Inherited
public @interface Test2 {
    int id();
}

Let’s consider two classes A and B where class B inherits class A.

@Test1(id = 100)
@Test2(id = 200)
public class A {
        // Code for class A goes here.
}
// class B inherits Test2(id = 200) annotation from class A.
public class B extends A {
       // Code for class B goes here.
}

In the above snippet of code, class B inherits @Test2(id = 200) annotation from class A because Test2 annotation type is annotated with an Inherited meta-annotation.

Class B does not inherit @Test1(id = 100) annotation because Test1 annotation type is not annotated with an Inherited meta-annotation.

@Retation Annotation


The @Retation annotation is a meta-annotation type that is used to specify how an instance of annotation type should be retained by Java. It is also known as retention policy of an annotation type.

An annotation can be retained at three levels in Java that are as follows:

  • Source code only
  • Class file only (default)
  • Class file and runtime (simply known as runtime)

If an annotation type has a “source code only” retention policy, instances of annotation type are discarded by the Java compiler when compiled into a class file.

If the retention policy is “class file only”, instances of annotation type are retained in the class file but they cannot be read at runtime by JVM.

If the retention policy is “class file and runtime”, instances of annotation are retained in the class file and they can be read at runtime by JVM.

For instance, the declaration of SuppressWarnings annotation type is annotated by @Retention with the value of SOURCE.

@Retention(value = SOURCE)
public @interface SuppressWarnings

If we do not declare Retention meta-annotation on an annotation type, its retention policy default to class file only. It means that we will not be able to read those annotations at runtime by JVM.

@Target Annotation


The @Target annotation is a type of meta annotation that is used to annotate an annotation type to specify the context in which annotation type can be used.

It has only one element named value. The value of Target can be one of the members of the java.lang.annotation.ElementType enum:

a) ANNOTATION_TYPE: The annotation can be used to annotate another annotation type declaration.

b) CONSTRUCTOR: The annotation can be used to annotate constructor declaration.

c) FIELD: The annotation can be used to annotate fields declaration and enum constants.

d) LOCAL_VARIABLE: The annotation can be used to annotate local variable declaration.

e) METHOD: The annotation can be used to annotate method declaration.

f) PACKAGE: The annotation can be used to annotate package declaration.

g) PARAMETER: It can be used to annotate parameter declaration.

h) TYPE: The annotation can be used to annotate annotation type, class, interface, and enum declarations.

For instance, the Override annotation type declaration is annotated with @Target annotation that will make @Override annotation only applicable to method declaration.

@Target(value = METHOD)
// Declaration of multiple values in the Target annotation.
@Target(value = {TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})

@Repeatable Annotation

Most annotations can be applied only once to a class, method, field, etc. In some cases, we need to apply an annotation more than once.

But prior to Java 8, it is not allowed to repeat an annotation more than one time. To overcome this problem, Java 8 added @Repeatable annotation.

The @Repeatable annotation added in Java 8 version is meta-annotation type that is used to annotate annotation type if its repeated use has to be.

The Repeatable annotation has only one element named value whose type will be a class type of another annotation type.

Look at the below code where A is annotated with @Repeatable(B.class) annotation, which means that it is a repeatable annotation type and its containing annotation type is B.

// A repeatable annotation type that contains B as Containing annotation type.
package annotationsProgram;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
@Repeatable(B.class)
public @interface A 
{
    String date();
}
// A Containing annotation type for A Repeatable annotation type.
package annotationsProgram;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface B {
	A[ ] value();
}

We can use A annotation to log change history for the Test class, as shown below:

package annotationsProgram;
@A(date="28/09/2021")
@A(date="08/10/2021")
public class Test {
public static void process()
{
    // code goes here.
 }
}

@Native Annotation


The @Native annotation is a type of meta-annotation that is used to annotate fields. It is a marker annotation that indicates that the annotated field may be referenced from the native code.


Hope that this tutorial has covered all important kind of annotations in java with example. I hope that you will have understood the basic concepts of Java annotations.
Thanks for reading!!!
Next ⇒ Custom Annotation in Java⇐ Prev Next ⇒