Java annotation
| Company type | Language feature |
|---|---|
| Industry | Software development |
| Founded | September 2004 |
| Products | Annotations for Java programming language |
In the context of the Java programming language, an annotation refers to syntactic metadata embedded within Java source code, functioning similarly to an attribute. These annotations can be applied to classes, methods, variables, parameters, and Java packages. Unlike Javadoc tags, which exist solely in source files, Java annotations are preserved within compiled Java class files. This feature allows them to be retained by the Java virtual machine during runtime and accessed through reflection. Additionally, developers have the capability to define meta-annotations derived from pre-existing ones.
History
Prior to the introduction of formal annotations, the Java platform relied on various informal methods such as the transient modifier and the @Deprecated tag used in Javadoc comments. The Java Specification Request JSR-175 brought forth a comprehensive annotation framework to the Java Community Process in 2002, receiving official endorsement in September 2004.
Annotations became an integral part of Java starting with JDK version 1.5. The initial support for compile-time annotation processing was provided by the apt tool in JDK 1.5; this functionality was later standardized under JSR-269 and incorporated directly into the javac compiler by version 1.6.
Similarly, in C++26, annotation capabilities facilitating reflection were introduced, mirroring Java’s methodology.
Built-in annotations
The Java language offers seven predefined standard annotations. Of these, three belong to the java.lang package, while four originate from java.lang.annotation.
Annotations for Java code usage:
@Override— Verifies that a method overrides a method from a superclass or interface, generating a compilation error if it does not.@Deprecated— Flags methods as outdated, prompting warnings during compilation when such methods are utilized.@SuppressWarnings— Eliminates specified compiler warnings.
Meta-Annotations (used on other annotations):
@Retention— Specifies the duration an annotation is retained, whether in source code, class files, or at runtime.@Documented— Ensures that an annotation appears in generated documentation.@Target— Limits the types of Java elements to which an annotation can be applied.@Inherited— Permits annotations to be inherited by subclasses.
Since Java 7, three additional annotations have been introduced:
@SafeVarargs— Suppresses warnings for methods or constructors that use generic variable arguments.@FunctionalInterface— Denotes that a type declaration is intended to be a functional interface (introduced in Java 8).@Repeatable— Enables multiple instances of the same annotation on a single declaration (introduced in Java 8).
Built-in annotations
This illustration demonstrates the use of the @Override annotation, which directs the compiler to check for proper method overriding. In this case, a compilation failure arises because the gettype() method in the Cat class does not correctly override Animal’s getType() method due to a difference in letter casing. Omitting this annotation would cause the compiler to treat it as a new method, allowing the mistake to pass unnoticed.
<syntaxhighlight lang="java"> public class Animal {
public void speak() {
}
public String getType() {
return "Generic animal";
}
}
public class Cat extends Animal {
@Override
public void speak() { // Proper override.
System.out.println("Meow.");
}
@Override
public String gettype() { // Compilation error: should be getType().
return "Cat";
}
} </syntaxhighlight>
Custom annotations
Defining an annotation type is similar to declaring an interface and begins with an at-symbol (@):
<syntaxhighlight lang=Java>
@Twizzle
public void toggle() {
}
public @interface Twizzle {
}
</syntaxhighlight>
Annotations can contain key-value pairs represented as methods with restricted return types such as primitives, String, Class, enums, other annotations, or arrays of these types. These methods may also specify default values:
<syntaxhighlight lang=Java>
@Edible(true) Item item = new Carrot();
public @interface Edible {
boolean value() default false;
}
@Author(first = "Oompah", last = "Loompah") Book book = new Book();
public @interface Author {
String first();
String last();
}
</syntaxhighlight>
Annotations themselves can be annotated to define their retention policy and applicable targets:
<syntaxhighlight lang=Java>
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Tweezable {
}
</syntaxhighlight>
Certain annotations such as @Deprecated, @Override, and @SuppressWarnings are reserved by the compiler for syntactic purposes.
Many frameworks leverage annotations to assign behaviors directly to classes and methods without relying on external configuration or API calls. For instance, in Java Persistence API (JPA), entity classes use annotations to map objects to database tables:
<syntaxhighlight lang=Java> @Entity @Table(name = "people") public class Person implements Serializable {
@Id @GeneratedValue(strategy = GenerationType.AUTO) private Integer id;
@Column(length = 32) private String name;
// Getters and setters omitted for brevity
} </syntaxhighlight>
At runtime, frameworks like JPA process these annotations to facilitate object-relational mapping.
Complete examples of annotation declarations include:
<syntaxhighlight lang=Java> @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR,
ElementType.ANNOTATION_TYPE, ElementType.PACKAGE,
ElementType.FIELD, ElementType.LOCAL_VARIABLE})
@Inherited public @interface Unfinished {
enum Priority { LOW, MEDIUM, HIGH }
String value();
String[] changedBy() default "";
String[] lastChangedBy() default "";
Priority priority() default Priority.MEDIUM;
String createdBy() default "James Gosling";
String lastChanged() default "2011-07-08";
} </syntaxhighlight>
<syntaxhighlight lang=Java> public @interface UnderConstruction {
String owner() default "Patrick Naughton"; String value() default "Object is Under Construction."; String createdBy() default "Mike Sheridan"; String lastChanged() default "2011-07-08";
} </syntaxhighlight>
An example from a business application involves validation logic where custom annotations indicate development status:
<syntaxhighlight lang=Java> @UnderConstruction(owner="Jon Doe") public class DateValidator implements Validator {
public void validate(FacesContext context, UIComponent component, Object value)
throws ValidatorException {
String date = (String) value;
String errorLabel = "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
)
FacesMessage message = new FacesMessage();
message.setSeverity(FacesMessage.SEVERITY_ERROR);
message.setSummary(errorLabel);
message.setDetail(errorLabel);
throw new ValidatorException(message);
}
}
} </syntaxhighlight>
Processing
During the compilation of Java source code, annotations may be handled by specialized compiler extensions known as annotation processors. These processors can produce informational outputs or generate supplementary Java source files and resources, which are subsequently compiled and processed further. It is important to note that annotation processors do not have the capability to alter the annotated source code itself. When an annotation is marked with a RetentionPolicy of either CLASS or RUNTIME, the Java compiler embeds its metadata within the resulting class files. This metadata can later be accessed by the JVM or other tools to influence how program components behave or interact.
In addition to annotation processors, Java developers can utilize reflection to work with annotations at runtime. Introduced in Java SE 5, the AnnotatedElement interface resides in the java.lang.reflect package and is implemented by reflection classes such as Class, Constructor, Field, Method, and Package. This interface provides methods like getAnnotation, getAnnotations, and isAnnotationPresent, enabling access to annotations retained at runtime. Since annotations are compiled into class files similarly to regular classes, they can be queried and manipulated as standard Java objects.
Example illustrating the creation and handling of a custom annotation:
<syntaxhighlight lang=Java> import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME) public @interface TypeHeader {
String developer() default "Unknown"; String lastModified(); String[] teamMembers(); int meaningOfLife();
} </syntaxhighlight>
Applying this annotation to a class:
<syntaxhighlight lang=Java> @TypeHeader(developer = "Bob Bee",
lastModified = "2013-02-12",
teamMembers = { "Ann", "Dan", "Fran" },
meaningOfLife = 42)
public class SetCustomAnnotation {
// Class contents
} </syntaxhighlight>
Reflective processing of the annotation:
<syntaxhighlight lang=Java> import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement;
public class UseCustomAnnotation {
public static void main(String[] args) {
Class<SetCustomAnnotation> clazz = SetCustomAnnotation.class;
displayAnnotation(clazz);
}
static void displayAnnotation(AnnotatedElement element) {
try {
if (element.isAnnotationPresent(TypeHeader.class)) {
Annotation annotationInstance = element.getAnnotation(TypeHeader.class);
TypeHeader header = (TypeHeader) annotationInstance;
System.out.println("Developer: " + header.developer());
System.out.println("Last Modified: " + header.lastModified());
System.out.print("Team members: ");
for (String member : header.teamMembers())
System.out.print(member + ", ");
System.out.println();
System.out.println("Meaning of Life: " + header.meaningOfLife());
}
} catch (Exception e) {
e.printStackTrace();
}
}
} </syntaxhighlight>
See also
- Jakarta Annotations
- CLI Attributes
- Java
- Java virtual machine
- Model-driven architecture
- Python decorators, which draw inspiration from Java annotations and share a comparable syntax.