Defining annotation types


Annotations

In Java, an annotation is a form of syntactic metadata that can be added to Java source code. It provides data about a program that is not part of the program itself. Annotations have no direct effect on the operation of the code they annotate. Classes, methods, variables, parameters and packages are allowed to be annotated.


The idea behind Annotations

The Java Language Specification describes Annotations as follows:

  • An annotation is a marker which associates information with a program construct, but has no effect at run time.

Annotations may appear before types or declarations. It is possible for them to appear in a place where they could apply to both a type or a declaration.

What exactly an annotation applies to is governed by the "meta-annotation" @Target. See "Defining annotation types" for more information.

Annotations are used for a multitude of purposes. Frameworks like Spring and Spring-MVC make use of annotations to define where Dependencies should be injected or where requests should be routed.

Other frameworks use annotations for code-generation. Lombok and JPA are prime examples, that use annotations to generate Java (and SQL) code.

This topic aims to provide a comprehensive overview of:

  • How to define your own Annotations?
  • What Annotations does the Java Language provide?
  • How are Annotations used in practice?

Defining annotation types

Annotation types are defined with @interface. Parameters are defined similar to methods of a regular interface.

@interface MyAnnotation {
     String param1();
     boolean param2();
     int[] param3(); // array parameter
}

Default values

@interface MyAnnotation {
    String param1() default "someValue";
    boolean param2() default true;
    int[] param3() default {};
}

Meta-Annotations

Meta-annotations are annotations that can be applied to annotation types. Special predefined meta-annotation define how annotation types can be used.

@Target

The @Target meta-annotation restricts the types the annotation can be applied to.

@Target(ElementType.METHOD)
@interface MyAnnotation {
    // this annotation can only be applied to methods
}

Multiple values can be added using array notation, e.g. @Target({ElementType.FIELD, ElementType.TYPE})

Available Values

ElementType Target Example Usage on Target Element
ANNOTATION_TYPE annotation types @Retention(RetentionPolicy.RUNTIME) @interface MyAnnotation {}
CONSTRUCTOR constructors @MyAnnotation public MyClass() {}
FIELD fields, enum constants @XmlAttribute private int count;
LOCAL_VARIABLE variable declarations inside methods for (@LoopVariable int i = 0; i < 100; i++) { @Unused String resultVariable; }
PACKAGE package (in package-info.java) @Deprecated package very.old;
METHOD methods @XmlElement public int getCount() {...}
PARAMETER method/constructor parameters public Rectangle(@NamedArg("width") double width, @NamedArg("height") double height) {...}
TYPE classes, interfaces, enums @XmlRootElement public class Report {}

Version ≥ Java SE 8
ElementType target example usage on target element
TYPE_PARAMETER Type parameter declarations public <@MyAnnotation T> void f(T t) {}
TYPE_USE Use of a type Object o = "42";ing s = (@MyAnnotation String) o;

@Retention

The @Retention meta-annotation defines the annotation visibility during the applications compilation process or execution. By default, annotations are included in .class files, but are not visible at runtime. To make an annotation accessible at runtime, RetentionPolicy.RUNTIME has to be set on that annotation.

@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
    // this annotation can be accessed with reflections at runtime
}

Available Values

RetentionPolicy Effect
CLASS The annotation is available in the .class file, but not at runtime
RUNTIME The annotation is available at runtime and can be accessed via reflection
SOURCE The annotation is available at compile time, but not added to the .class files. The annotation can be used e.g. by an annotation processor.

@Documented

The @Documented meta-annotation is used to mark annotations whose usage should be documented by API documentation generators like javadoc. It has no values. With @Documented, all classes that use the annotation will list it on their generated documentation page. Without @Documented, it's not possible to see which classes use the annotation in the documentation.

@Inherited

The @Inherited meta-annotation is relevant to annotations that are applied to classes. It has no values. Marking an annotation as @Inherited alters the way that annotation querying works.

  • For a non-inherited annotation, the query only examines the class being examined.
  • For an inherited annotation, the query will also check the super-class chain (recursively) until an instance of the annotation is found.

Note that only the super-classes are queried: any annotations attached to interfaces in the classes hierarchy will be ignored.

@Repeatable

The @Repeatable meta-annotation was added in Java 8. It indicates that multiple instances of the annotation can be attached to the annotation's target. This meta-annotation has no values.


Runtime annotation checks via reflection

Java's Reflection API allows the programmer to perform various checks and operations on class fields, methods and annotations during runtime. However, in order for an annotation to be at all visible at runtime, the RetentionPolicy must be changed to RUNTIME, as demonstrated in the example below:

@interface MyDefaultAnnotation {
 
}
 
@Retention(RetentionPolicy.RUNTIME)
@interface MyRuntimeVisibleAnnotation {
 
}
 
public class AnnotationAtRuntimeTest {
 
	@MyDefaultAnnotation
	static class RuntimeCheck1 {
 
	}
 
	@MyRuntimeVisibleAnnotation
	static class RuntimeCheck2 {
 
	}
 
	public static void main(String[] args) {
		Annotation[] annotationsByType = RuntimeCheck1.class.getAnnotations();
		Annotation[] annotationsByType2 = RuntimeCheck2.class.getAnnotations();
 
		System.out.println("default retention: " + Arrays.toString(annotationsByType));
		System.out.println("runtime retention: " + Arrays.toString(annotationsByType2));
	}
}

Basic Programs