Java annotations are tags that we insert into source code for providing more information about the code. They associate information with the annotated program element. Beside Java annotations Java programs have copious amounts of informal documentation that is typically contained within comments in the source code file but annotations are different from comments they annotate the program elements directly using annotation types to describe the form of the annotations. Annotations present the information in a standard and structured way so that it could be used amenably by processing tools.
A Java annotation is a modifier starts with @
symbol as Javadoc tags do, followed by annotation-tag name followed by zero or more element-value pairs enclosed in parenthesis. There may be white space between @
symbol and the annotation-tag name but standard coding practices advice to avoid any space between the two. Annotations are processed by annotation processing tools [use reflection] to extract the provided information and to use that information for intended purpose. That's why Java annotations are called metadata about the code.
Java annotations can be extracted at the time of compiling the code by the compiler or at run time by annotation processors. However, Java compiler can understand only a few Java annotations and further to Java compiler we do need annotation processing tools either developed by ourselves or third party annotation processors to parse Java annotations.
The purpose of an annotation is to associate information with the annotated program element. An annotations may be used as modifiers in any declaration, whether package, class (including enums), interface (including annotation types), field, method, formal parameter, constructor, or local variable.
Annotations may also be used on enum
constants. Such annotations are placed immediately before the enum
constant they annotate. Java annotations are conventionally placed before all other modifiers, but this is not a compulsion; they may be freely intermixed with other modifiers.
However, you maybe familiar with Javadoc tags that embed metadata in Java source code but unlike Javadoc tags, Java annotations can be reflective and retrievable at run-time.
One of the main reasons for adding annotations to the Java platform is to enable development and runtime tools to have a common infrastructure in order to reduce the effort required for development and deployment. By having a common infrastructure metadata structure can be standardized, thus a tool could use the metadata information in form of annotations to generate additional source code, or to provide additional information for debugging, or other purposes.
Annotations to Java have been introduced first time in Java 1.5. Prior to Java 1.5, it was common to use naming patterns to indicate that some program elements demanded special treatment by a tool or framework. Naming patterns have disadvantages; they are not efficient to cope up with typographical errors. Second, there is no way to ensure that naming patterns are used only on appropriate program elements. Third disadvantage of naming patterns is that they provide no good way to associate parameter values with program elements. Java annotations solve all of these problems nicely. Java annotations have been covered in section 9.6 and 9.7 in Java Language Specification.
Java defines seven built-in annotations out of which three (@Override
, @Deprecated
, and @SuppressWarnings
) are applied to Java code and they are included in java.lang
library. These three annotations are called regular Java annotations. Rest four (@Retention
, @Documented
, @Target
, and @Inherited
) are applied to other annotations and they are included in java.lang.annotation
library. These annotations are called meta Java annotations. Meta Java annotations are used to create custom annotations. Custom annotations will be discussed shortly.
Following table shows the functionality of built-in annotations, and the library in which they are defined.
Annotation Name | Applicable To | Use | Included in |
---|---|---|---|
Java Annotations Applied to Java code | |||
@Override | Member Methods | Checks that this method overrides a method from its superclass | java.lang |
@Deprecated | All annotable items | Marks item as deprecated | java.lang |
@SuppressWarnings | All annotable items except packages and annotations | Suppress warning of given type | java.lang |
Java Annotations Applied to Other Annotations | |||
@Retention | Annotations | Specifies how long this annotation is retained - whether in code only, compiled into the class, or available at run time through reflection. | java.lang.annotation |
@Documented | Annotations | Specifies that this annotation should be included in the documentation of annotated items | java.lang.annotation |
@Target | Annotations | Specifies the items to which this annotation can be applied | java.lang.annotation |
@Inherited | Annotations | Specifies that this annotation, when applied to a class, is automatically inherited by its subclasses. | java.lang.annotation |
From the usage point of view annotations are categorized as Regular and Meta Annotations. Regular Annotations are applied to Java source code while Meta Annotations are applied to other Java annotations. Meta Annotations are also used for writing custom annotations; we will soon discuss custom annotations.
@Override
Java Annotation
The @Override
annotation applies only to methods. At the time of compilation the compiler checks that a method with @Override
annotation overrides the superclass's method or not. If yes, it is OK else it reports a compile time error. The retention policy for @Override
annotation is SOURCE
which means this annotation will be discarded completely after compiling the code and would not be included in .class
file or bytecode.
Retention policy for an annotation is the visibility of that annotation and it is of three types: CLASS
, RUNTIME
, and SOURCE
.
While compiling the following piece of code the compiler will report you an error because the equals
method does not override the equals
method of the Object
class. Method equals()
takes a parameter of type Object
, not Human
.
class Human { @Override public boolean equals(Human otherHuman) { //comparison code here return false; //mock return statement } }
@Deprecated
Java Annotation
While programming in eclipse IDE you may have seen some strikethrough method names. These methods are deprecated and their use is not encouraged any more because they could be dropped in further releases. The @Deprecated
Java annotation can be attached to any items whose use is no longer encouraged; it warns the programmer not to use this API or constant or any item that is marked deprecated. This Java annotation has the same role as the @deprecated
Javadoc tag. This Java annotation follows the RUNTIME
retention policy; therefore it is kept safe in bytecode and available for reflection at run time.
Note that there is a Javadoc tag also with the name @deprecated
but the Javadoc tag starts with a lowercase "d" and the Java annotation starts with an uppercase "D". Both @deprecated
and @Deprecated
are conceptually related.
The following piece of code will successfully compile but with warning deprecatedMethod()
in Human
has been deprecated.
class DeprecatedDemo { public static void main(String a[]) { Human h = new Human(); h.deprecatedMethod(); //deprecated } } class Human { @Deprecated public void deprecatedMethod() { System.out.println("It is deprecated method"); } }
@SuppressWarnings
Java Annotation
The @SuppressWarnings
Java annotation instructs compiler to suppress the warnings of a particular type that are shown during compilation. Note that the set of warnings suppressed in a given element is a superset of the warnings suppressed in all containing elements. For example, if you annotate a class to suppress one warning and annotate a method to suppress another, both warnings will be suppressed in the method.
As a matter of style, programmers should always use this Java annotation on the most deeply nested element where it is effective. If you want to suppress a warning in a particular method, you should only annotate that method rather than its class.
The retention policy for @SuppressWarnings
Java annotation is also SOURCE
; therefore it will be discarded after compiling the code and would not be included in .class
file.
@Target
Java Annotation
While defining a custom Java annotation we have to specify which element (class, method, field, constructor etc.) this newly defined annotation would be applicable on. The @Target
annotation is used for that purpose to set the target elements on which the custom annotation can be applied.
Table 2 shows possible values of elements for @Target
annotation. They belong to the enumerated type ElementType
. You can specify any number of element types, enclosed in braces.
Element Type | Annotation Applies To |
---|---|
ANNOTATION_TYPE | Annotation type declarations |
PACKAGE | Packages |
TYPE | Classes (including enum) and interfaces (including annotation types) |
METHOD | Methods |
CONSTRUCTOR | Constructors |
FIELD | Fields (including enum constants) |
PARAMETER | Method or constructor parameters |
LOCAL_VARIABLE | Local variables |
The compiler checks if the annotation has been applied to a permitted type only. If not then compile-time error occurs. And so, a Java annotation without @Target
restriction can be applied to any item.
@Retention
Java Annotation
As name suggets, @Retention
meta annotation specifies till what level an annotation will be retained. To decide the scope of the custom annotation we have to specify one of the three values (SOURCE
, CLASS
, or RUNTIME
) of RetentionPolicy
. The default is RetentionPolicy.CLASS
.
RetentionPolicy.SOURCE
specifies the scope of custom annotation to the compile time. Annotations having retention policy RetentionPolicy.SOURCE
are not included in bytecode.
Annotations those are carrying RetentionPolicy.CLASS
policy of retention are included in .class
files, but the virtual machine need not to load them.
Annotations having RetentionPolicy.RUNTIME
policy are included in class files and loaded by the virtual machine. Java annotations that are given RUNTIME
retention policy can be accessed at run time through the reflection API.
@Documented
Java Annotation
The @Documented
meta annotation hints Javadoc tool to include this annotation in the documentation wherever it is used. Documented Java annotations should be treated just like other modifiers, such as protected
or static
, for documentation purposes. The use of other annotations is not included in the documentation.
@Inherited
Java Annotation
The @Inherited
annotation can be applied only to annotations for classes. When a superclass is annotated with an @Inherited
Java annotation then all of its subclasses automatically have the same annotation.
As of now we have discussed built-in annotations provided by Java language. Sometimes we may need to design our own customized Java annotations depending upon the nature of requirement and parse them at run time to extract the information supplied by annotations. Java annotations that we design are called custom Java annotations.
Java annotation types are a special kind of interface
, declared with the interface
keyword preceded by the @
symbol. Java annotation types can be declared anywhere an interface
can be declared that is, as a top-level Java annotation type or nested within another type and can have the same modifiers applied as interfaces have. Characterizing Java annotation types as interfaces is a little misleading, however, as aside from borrowing some syntax and some associated usage rules, Java annotation types bear little resemblance to interfaces in normal use.
Each annotation is defined by an annotation interface, no matter it is custom or built-in Java annotation. An annotation definition may or may not have methods, if it has then the methods of interface corresponds to the elements of the annotation. For an example, we can define a simple custom @Author
Java annotation as follows.
@Target({ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.TYPE, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @interface Author { String author() default ""; }
annotation Author
defined above has one method author()
that by default returns a zero length string or the value provided by the programmer at the time of applying this annotation to supported element types. At run time a tool or your own program would call the author()
method to retrieve the author element of the Author annotation.
The Target
and Retention
Java annotations used while declaring Author
annotation are meta Java annotations. They annotate the Author
annotation, marking it as a Java annotation that can be applied to methods, constructors, classes, enums, and interfaces (including annotation types). Author
annotation is retained when the class file is loaded into memory by the virtual machine as its retention policy is RUNTIME
.
Let's now see how to use and access the value of author element of @Author
Java annotation in a program.
Before everything it must be noted that Java Annotation Retention Policy should be RUNTIME
otherwise annotated information will not be accessible at runtime and we won't be able to extract any data from it.
/* AccessAnnotations.java */ import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; public class AccessAnnotations { public static void main(String[] args) { Class<AnnotatedClass> ac = AnnotatedClass.class; try { Field f = ac.getDeclaredField("annotatedField"); Method mGetter = ac.getMethod("getAnnotatedField"); Method mSetter = ac.getMethod("setAnnotatedField", new Class[] {int.class}); Constructor<AnnotatedClass> cons = ac.getConstructor(); System.out.println("Class Author: " + ac.getAnnotation(Author.class).author()); System.out.println("Field Author: " + f.getAnnotation(Author.class).author()); System.out.println("Constructor Author: " + cons.getAnnotation(Author.class).author()); System.out.println("Getter Author: " + mGetter.getAnnotation(Author.class).author()); System.out.println("Setter Author: " + mSetter.getAnnotation(Author.class).author()); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } catch (NoSuchFieldException e) { e.printStackTrace(); } } } @Author (author = "Krishan Class") class AnnotatedClass { @Author (author = "Krishan Field") private int annotatedField; @Author (author = "Krishan Constructor") public AnnotatedClass() { System.out.println("Object created"); annotatedField = 10; } @Author (author = "Krishan Getter") public int getAnnotatedField() { return annotatedField; } @Author (author = "Krishan Setter") public void setAnnotatedField(int annotatedField) { this.annotatedField = annotatedField; } } @Target({ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.TYPE, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @interface Author { String author () default ""; } OUTPUT ------ Class Author: Krishan Class Field Author: Krishan Field Constructor Author: Krishan Constructor Getter Author: Krishan Getter Setter Author: Krishan Setter
You can think above Java program an annotation parser. While reading the program you may find a few things new if you have not used java.lang.reflect
package of Java so far. The main
method of AccessAnnotations
acts like a Java annotation parsing tool. It accesses the AnnotatedClass
members with help of reflection classes such as Field
, Constructor
, and Method
etc and parses the meta information provided along with AnnotatedClass
and its members.
For example, in statement Field f = ac.getDeclaredField ("annotatedField");
the class Field
belongs to java.lang.reflect
package and the object f
of type Field
provides information about, and access to the private
field annotatedField
of class AnnotatedClass
. Then you can call getAnnotation
method on f
to access the annotation information attached to annotatedField
. There may be more than one Java annotations attached to one field so you need to pass the Annotation
type as a parameter to getAnnotation
in order to get the specified type annotation if such a Java annotation is present, else null.
In this tutorial we discussed how to write and process user defined custom annotations in Java. Java annotations add metadata to Java source code. Java annotations can be accessed at run-time by using reflection. Hope you have enjoyed reading this tutorial, please do write us if you have any suggestion/comment or come across any error on this page. Thanks for reading!
Share this page on WhatsApp