Java annotations are supplements and metadata to the Java compiler, they can be added to classes, methods, fields, parameters, and packages. Although they do not affect the code execution, they can change the way a program is treated by the compiler, they can be an alternative to the Java marker interface. Annotations start with @ and are implicitly public. Attempting to declare an annotation with private or protected will result in a compilation error as they can’t have access modifier beyond default public.

Built in annotation

AnnotationApplicationDescription
@OverrideMethodIndicates that a method is intended to override a method in a superclass
@DecprecatedMethod, class, fieldMarks a method, class, or field as deprecated, single that it should no longer be used
@SupressWarningsMethod, class, field, local variable, parameterInstructs the compiler to suppress specific warnings (e.g. unchecked warnings)
@SafeVarArgsFinal, static, prive methodSuppresses unchecked warnings in a method or constructor with a variable number of arguments
@FunctionalInterfaceInterfaceMarks an interface as a functional interface

Custom annotation

You can define your custom annotations using the @interface keyword. We will use Java reflection API in the examples in this page to inspect and process annotations.

Meta-annotation

Meta-annotations are used to define behaviour for custom annotations. These are:

  • @Target
  • @Retention
  • @Inherited
  • @Documented

@Retention

@Retention annotation is used to specify to what level annotation will be available. If you do not specify @Retention, the annotation will default to RetentionPolicy.CLASS.

RetentionPolicyAvailability
RetentionPolicy.SOURCERefers to the source code. It will not be available in the compiled class; the annotation will be discarded during compilation (it will only matter before the code is even compiled e.g. @SupressWarnings)
RetentionPolicy.CLASSRefers to the .class file, available to java compiler but not to JVM. It is included in the class file; the annotation will be kept around through compilation but discarded at runtime
RetentionPolicy.RUNTIMERefers to the runtime, available to java compiler and JVM; annotation will be kept around through the actual running of your program

@Target

@Target tag is used to specify at which type, the annotation is used. The java.lang.annotation.ElementType enum declares many constants to specify the type of element where annotation is to be applied such as TYPE, METHOD, FIELD etc. If you do not specify @Target, the annotation can be applied to any element (classes, methods, fields, parameters, etc.).

Element TypesWhere the annotation can be applied
TYPEClass, interface or enumeration
FIELDFields
METHODMethods
CONSTRUCTORConstructors
LOCAL_VARIABLELocal variables
ANNOTATION_TYPEAnnotation type
PARAMETERParameter

Marker annotation

An annotation that has no method, is called marker annotation. The @Override and @Deprecated are marker annotations.

import java.lang.annotation.*;
 
@Target(ElementType.TYPE) 
@Retention(RetentionPolicy.RUNTIME)
public @interface VeryImportant{ }
  • @Target(ElementType.TYPE): Restricts the annotation to be used only on classes, interfaces, or enums.
  • @Retention(RetentionPolicy.RUNTIME): Specifies that the annotation is available at runtime and can be accessed through reflection.
@VeryImportant
public class Person {
	String name;
	public Person(String name) {
		this.name = name;
	}
}
 
public class Demo {
	public static void main() {
		Person p = new Person("John");
        if (p.getClass().isAnnotationPresent(VeryImportant.class)) {
            System.out.println("Very important person");
        } else {
            System.out.println("Not very important person");
        }
	}
}
Very important person

The class Person is annotated with @VeryImportant. The reflection is used here to check if the @VeryImportant annotation is present on the class object of p. (reflection requires that the annotation has a @Retention(RetentionPolicy.RUNTIME) declaration to perform checks at runtime). The isAnnotationPresent() method will return true if the Person class is annotated with @VeryImportant, false otherwise.

Annotation with values

The annotation can include values (elements), which can be named or unnamed.

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RunImmediately {  
	int times();  
}

We can provide the default value also.

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RunImmediately {  
	int times() default 1;  
}

This annotation RunImmediately can be applied to method and available at runtime. It includes a single attribute, times, which specifies how many times a method should be invoked when this annotation is applied.

  • default 1: If times is not explicitly set, it will default to 1.

Consider the below demonstration.

public class Person {
    String name;
    
    public Person(String name) {
        this.name = name;
    }
        
    @RunImmediately(times = 3)
    public void eat() {
        System.out.println(name + " is eating");
    }
}
 
public class Demo {
	public static void main(String[] args) throws Exception {
        Person p = new Person("John");
        Method eatMethod = Person.class.getMethod("eat");
        if (eatMethod.isAnnotationPresent(RunImmediately.class)) {
            RunImmediately runImmediately = eatMethod.getAnnotation(RunImmediately.class);
            for (int i = 0; i < runImmediately.times(); i++) {
                eatMethod.invoke(p);
            }
        }
	}
}
John is eating
John is eating
John is eating

The eat() method in the Person class is annotated with @RunImmediately(times = 3), with the attribute times value set to 3. The reflection code is used in the main method to retrieve the eat() method from the Person class Person.class.getMethod("eat"). The if statement checks whether the @RunImmediately annotation is present on the eat() method. The code eatMethod.getAnnotation(RunImmediately.class) retrieves the RunImmediately annotation instance from the method. In the for loop, runImmediately.times() extracts the value of the times attribute from the annotation (in this case, 3). eatMethod.invoke(p) dynamically invokes the eat() method on the Person object p for times times, as specified in the annotation.

Multi-value annotation

An annotation that has more than one method, is called Multi-Value annotation. (Annotations are implicitly public, can be applied to any element and available at runtime when meta annotations are not specified)

 @interface MyAnnotation{  
	int value1();  
	String value2();  
	String value3();  
}  

We can provide the default value also. For example:

 @interface MyAnnotation{  
	int value1() default 1;  
	String value2() default "";  
	String value3() default "xyz";  
}  
@MyAnnotation(value1=22,value2="John Doe",value3="South Africa")

Back to parent page: Java Standard Edition (Java SE) and Java Programming

Web_and_App_Development Programming_Languages Java Annotation Reflection

Reference: