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
Annotation
Application
Description
@Override
Method
Indicates that a method is intended to override a method in a superclass
@Decprecated
Method, class, field
Marks a method, class, or field as deprecated, single that it should no longer be used
@SupressWarnings
Method, class, field, local variable, parameter
Instructs the compiler to suppress specific warnings (e.g. unchecked warnings)
@SafeVarArgs
Final, static, prive method
Suppresses unchecked warnings in a method or constructor with a variable number of arguments
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.
RetentionPolicy
Availability
RetentionPolicy.SOURCE
Refers 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.CLASS
Refers 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.RUNTIME
Refers 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 Types
Where the annotation can be applied
TYPE
Class, interface or enumeration
FIELD
Fields
METHOD
Methods
CONSTRUCTOR
Constructors
LOCAL_VARIABLE
Local variables
ANNOTATION_TYPE
Annotation type
PARAMETER
Parameter
Marker annotation
An annotation that has no method, is called marker annotation. The @Override and @Deprecated are marker annotations.
@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.
@VeryImportantpublic 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.
Single element annotation
If there is just one element named value, then the name can be omitted.
@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)@interface Author { String value(); // Single element named 'value'}
@Author("John Doe") // No need to write 'value = "John Doe"'public void someMethod() { System.out.println("Method written by John Doe");}
It is legal to use single-element annotations for annotation interfaces with multiple elements, so long as one element is named value and all other elements have default values.
@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: