In the Java computer programming language, an annotation is a form of syntactic metadata that can be added to Java source code, like an attribute. [1] Classes, methods, variables, parameters and Java packages may be annotated. Like Javadoc tags, Java annotations can be read from source files. Unlike Javadoc tags, Java annotations can also be embedded in and read from Java class files generated by the Java compiler. This allows annotations to be retained by the Java virtual machine at run-time and read via reflection. [2] It is possible to create meta-annotations out of the existing ones in Java. [3]
The Java platform has various ad-hoc annotation mechanisms—for example, the transient
modifier, or the @Deprecated
javadoc tag. The Java Specification Request JSR-175 introduced the general-purpose annotation (also known as metadata) facility to the Java Community Process in 2002; it gained approval in September 2004. [4]
Annotations became available in the language itself beginning with version 1.5 of the Java Development Kit (JDK). The apt
tool provided a provisional interface for compile-time annotation processing in JDK version 1.5; JSR-269 formalized this, and it became integrated into the javac compiler in version 1.6.
In C++26, C++ added annotations for reflection that are similar to Java annotations.
Java defines a set of annotations that are built into the language. Of the seven standard annotations, three are part of java.lang, and the remaining four are imported from java.lang.annotation. [5] [6]
Annotation | Package | Description |
---|---|---|
@Deprecated | java.lang | Marks the method as obsolete. Causes a compile warning if the method is used. |
@FunctionalInterface | java.lang | Marks an interface as intended to be a functional interface. |
@Override | java.lang | Marks that the method overrides an ancestor class-defined method. Causes a compilation error if the method is not found in one of the parent classes or implemented interfaces. |
@SafeVarargs | java.lang | Suppress warnings for all callers of a method or constructor with a generics varargs parameter, since Java 7. |
@SuppressWarnings | java.lang | Instructs the compiler to suppress the compile time warnings specified in the annotation parameters. |
@Documented | java.lang.annotation | Marks another annotation for inclusion in the documentation. |
@Inherited | java.lang.annotation | Marks another annotation to be inherited to subclasses of annotated class (by default annotations are not inherited by subclasses). |
@Native | java.lang.annotation | Marks a field defining a constant value as potentially being referenced from native code. |
@Repeatable | java.lang.annotation | Marks another annotation as repeatable. |
@Retention | java.lang.annotation | Specifies how the marked annotation is stored, whether in code only, compiled into the class, or available at runtime through reflection. |
@Target | java.lang.annotation | Marks another annotation to restrict what kind of Java elements the annotation may be applied to. |
In Jakarta EE (formerly Java Platform, Enterprise Edition), the following annotations also exist in jakarta.annotation
(formerly javax.annotation
): [7] [8]
Annotation | Package | Description |
---|---|---|
@Generated | jakarta.annotation | Marks source code that has been generated (i.e. not written by a user, or automatically generated by a computer). |
@Resource | jakarta.annotation | Marks a class, method, or field as a reference to a resource. |
@Resources | jakarta.annotation | Declares reference to resources, as a container for multiple resource declarations. |
@PostConstruct | jakarta.annotation | Marks a method to indicate that it must be executed after dependency injection to perform initialization, i.e. the method must be invoked before the class is used. |
@PreDestroy | jakarta.annotation | Marks a method as a callback notification to indicate the instance is in the process of being removed by the container, i.e. the method is used to release resources held by the instance. |
@Priority | jakarta.annotation | Marks any program element to indicate in what order they should be used. |
@Nonnull | jakarta.annotation | Marks any element that cannot be null . |
@Nullable | jakarta.annotation | Marks any element that has the explicit possibility of being null . |
@RunAs | jakarta.annotation | Defines the security role of the application during execution in a Jakarta EE container. |
@RolesAllowed | jakarta.annotation.security | Marks a method to specify security roles permitted to access the method. |
@PermitAll | jakarta.annotation.security | Marks a method to specify that all security roles may access the method. |
@DenyAll | jakarta.annotation.security | Marks a method to specify that no security roles may access the method. |
@DeclareRoles | jakarta.annotation.security | Specifies security roles used by the application. |
@DataSourceDefinition | jakarta.annotation.sql | Defines a container DataSource that is registered with Java Naming and Directory Interface (JNDI). |
@DataSourceDefinitions | jakarta.annotation.sql | Declares a container DataSource , acting as a container for multiple data source declarations. |
There was previously an annotation, @ManagedBean
, located in jakarta.annotation
, which was historically used to declare a Managed Bean which are container managed objects that support a small set of basic services such as resource injection, lifecycle callbacks and interceptors. However, it has been removed. [9] [10]
This example demonstrates the use of the @Override
annotation. It instructs the compiler to check parent classes for matching methods. In this case, an error is generated because the gettype()
method of class Cat doesn't in fact override getType()
of class Animal like is desired, because of the mismatching case. If the @Override
annotation were absent, a new method of name gettype()
would be created in class Cat.
publicclassAnimal{publicvoidspeak(){}publicStringgetType(){return"Generic animal";}}publicclassCatextendsAnimal{@Overridepublicvoidspeak(){// This is a good override.System.out.println("Meow.");}@OverridepublicStringgettype(){// Compile-time error due to typo: should be getType() not gettype().return"Cat";}}
Annotation type declarations are similar to normal interface declarations. An at-sign (@) precedes the keyword "interface".
// @Twizzle is an annotation to method toggle().@Twizzlepublicvoidtoggle(){}// Declares the annotation Twizzle.public@interfaceTwizzle{}
Annotations may include a set of key-value pairs, which are modeled as methods of the annotation type. Each method declaration defines an element of the annotation type. Method declarations must not have any parameters or a throws clause. Return types are restricted to primitives, String, Class, enums, annotations, and arrays of the preceding types. Methods can have default values.
// Same as: @Edible(value = true)@Edible(true)Itemitem=newCarrot();public@interfaceEdible{booleanvalue()defaultfalse;}@Author(first="Oompah",last="Loompah")Bookbook=newBook();public@interfaceAuthor{Stringfirst();Stringlast();}
Annotations themselves may be annotated to indicate where and when they can be used:
@Retention(RetentionPolicy.RUNTIME)// Make this annotation accessible at runtime via reflection.@Target({ElementType.METHOD})// This annotation can only be applied to class methods.public@interfaceTweezable{}
The compiler reserves a set of special annotations (including @Deprecated
, @Override
and @SuppressWarnings
) for syntactic purposes.
Annotations are often used by frameworks as a way of conveniently applying behaviours to user-defined classes and methods that must otherwise be declared in an external source (such as an XML configuration file) or programmatically (with API calls). The following, for example, is an annotated JPA data class:
@Entity// Declares this an entity bean@Table(name="people")// Maps the bean to SQL table "people"publicclassPersonimplementsSerializable{@Id// Map this to the primary key column.@GeneratedValue(strategy=GenerationType.AUTO)// Database will generate new primary keys, not us.privateIntegerid;@Column(length=32)// Truncate column values to 32 characters.privateStringname;publicIntegergetId(){returnid;}publicvoidsetId(Integerid){this.id=id;}publicStringgetName(){returnname;}publicvoidsetName(Stringname){this.name=name;}}
The annotations are not method calls and will not, by themselves, do anything. Rather, the class object is passed to the JPA implementation at run-time, which then extracts the annotations to generate an object–relational mapping.
A complete example is given below:
packagecom.acme.proj.annotation;importjava.lang.annotation.Documented;importjava.lang.annotation.ElementType;importjava.lang.annotation.Inherited;importjava.lang.annotation.Retention;importjava.lang.annotation.RetentionPolicy;importjava.lang.annotation.Target;@Documented@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.TYPE,ElementType.METHOD,ElementType.CONSTRUCTOR,ElementType.ANNOTATION_TYPE,ElementType.PACKAGE,ElementType.FIELD,ElementType.LOCAL_VARIABLE})@Inheritedpublic@interfaceUnfinished{publicenumPriority{LOW,MEDIUM,HIGH}Stringvalue();String[]changedBy()default"";String[]lastChangedBy()default"";Prioritypriority()defaultPriority.MEDIUM;StringcreatedBy()default"James Gosling";StringlastChanged()default"2011-07-08";}
packagecom.acme.proj.annotation;public@interfaceUnderConstruction{Stringowner()default"Patrick Naughton";Stringvalue()default"Object is Under Construction.";StringcreatedBy()default"Mike Sheridan";StringlastChanged()default"2011-07-08";}
packagecom.acme.proj.validators;importjavax.faces.application.FacesMessage;importjavax.faces.component.UIComponent;importjavax.faces.context.FacesContext;importjavax.faces.validator.Validator;importjavax.faces.validator.ValidatorException;importcom.acme.proj.annotation.UnderConstruction;importcom.acme.proj.annotation.Unfinished;importcom.acme.proj.annotation.Unfinished.Priority;importcom.acme.proj.util.Util;@UnderConstruction(owner="Jon Doe")publicclassDateValidatorimplementsValidator{publicvoidvalidate(FacesContextcontext,UIComponentcomponent,Objectvalue)throwsValidatorException{Stringdate=(String)value;StringerrorLabel="Please enter a valid date.";if(!component.getAttributes().isEmpty()){errorLabel=(String)component.getAttributes().get("errordisplayval");}if(!Util.validateAGivenDate(date)){@Unfinished(changedBy="Steve",value="whether to add message to context or not, confirm",priority=Priority.HIGH)FacesMessagemessage=newFacesMessage();message.setSeverity(FacesMessage.SEVERITY_ERROR);message.setSummary(errorLabel);message.setDetail(errorLabel);thrownewValidatorException(message);}}}
When Java source code is compiled, annotations can be processed by compiler plug-ins called annotation processors. Processors can produce informational messages or create additional Java source files or resources, which in turn may be compiled and processed. However, annotation processors cannot modify the annotated code itself. (Code modifications may be implemented using methods beyond the Java Language Specification.) The Java compiler conditionally stores annotation metadata in the class files, if the annotation has a RetentionPolicy
of CLASS
or RUNTIME
. Later, the JVM or other programs can look for the metadata to determine how to interact with the program elements or change their behavior.
In addition to processing an annotation using an annotation processor, a Java programmer can write their own code that uses reflection to process the annotation. Java SE 5 supports a new interface that is defined in the java.lang.reflect
package. This package contains the interface called AnnotatedElement
that is implemented by the Java reflection classes including Class
, Constructor
, Field
, Method
, and Package
. The implementations of this interface are used to represent an annotated element of the program currently running in the Java Virtual Machine. This interface allows annotations to be read reflectively.
The AnnotatedElement
interface provides access to annotations having RUNTIME
retention. This access is provided by the getAnnotation
, getAnnotations
, and isAnnotationPresent
methods. Because annotation types are compiled and stored in byte code files just like classes, the annotations returned by these methods can be queried just like any regular Java object. A complete example of processing an annotation is provided below:
importjava.lang.annotation.Retention;importjava.lang.annotation.RetentionPolicy;// This is the annotation to be processed// Default for Target is all Java Elements// Change retention policy to RUNTIME (default is CLASS)@Retention(RetentionPolicy.RUNTIME)public@interfaceTypeHeader{// Default value specified for developer attributeStringdeveloper()default"Unknown";StringlastModified();String[]teamMembers();intmeaningOfLife();}
// This is the annotation being applied to a class@TypeHeader(developer="Bob Bee",lastModified="2013-02-12",teamMembers={"Ann","Dan","Fran"},meaningOfLife=42)publicclassSetCustomAnnotation{// Class contents go here}
// This is the example code that processes the annotationimportjava.lang.annotation.Annotation;importjava.lang.reflect.AnnotatedElement;publicclassUseCustomAnnotation{publicstaticvoidmain(String[]args){Class<SetCustomAnnotation>classObject=SetCustomAnnotation.class;readAnnotation(classObject);}staticvoidreadAnnotation(AnnotatedElementelement){try{System.out.println("Annotation element values: %n");if(element.isAnnotationPresent(TypeHeader.class)){// getAnnotation returns Annotation typeAnnotationsingleAnnotation=element.getAnnotation(TypeHeader.class);TypeHeaderheader=(TypeHeader)singleAnnotation;System.out.printf("Developer: %s%n",header.developer());System.out.printf("Last Modified: %s%n",header.lastModified());// teamMembers returned as String[]System.out.print("Team members: ");for(Stringmember:header.teamMembers()){System.out.printf("%s, ",member);}System.out.println();System.out.println("Meaning of Life: %s%n",header.meaningOfLife());}}catch(Exceptionexception){exception.printStackTrace();}}}