Java Custom Annotations
A custom annotation is a small data label a program defines for its own classes. An annotation carries data about code, and it never carries behaviour.
An annotation read back at runtime
The Info annotation labels the Engine class with an author and a version. Reflection reads both values back and prints them.
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
public class Main {
public static void main(String[] args) {
Info info = Engine.class.getAnnotation(Info.class);
System.out.println(info.author());
System.out.println(info.version());
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface Info {
String author();
int version();
}
@Info(author = "Mira Chen", version = 2)
class Engine {
}A class without the annotation
The Plain class carries no Info label. isAnnotationPresent answers false, and the program prints its own line for the missing label.
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
public class Main {
public static void main(String[] args) {
System.out.println(Plain.class.isAnnotationPresent(Info.class));
Info info = Plain.class.getAnnotation(Info.class);
if (info == null) {
System.out.println("no info");
} else {
System.out.println(info.author());
}
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface Info {
String author();
int version();
}
class Plain {
}Example
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
public class Main {
public static void main(String[] args) {
Class<?>[] parts = {Engine.class, Brake.class, Wheel.class};
for (Class<?> part : parts) {
Info info = part.getAnnotation(Info.class);
if (info == null) {
System.out.println(part.getSimpleName() + ": no info");
} else {
System.out.println(part.getSimpleName() + ": " + info.author() + " v" + info.version());
}
}
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface Info {
String author();
int version();
}
@Info(author = "Mira Chen", version = 2)
class Engine {
}
@Info(author = "Theo Park", version = 1)
class Brake {
}
class Wheel {
}Key points
- The @interface keyword defines an annotation type.
- Annotation elements look like methods with no parameters. Each element holds one value.
- Retention sets how far an annotation travels. RUNTIME retention keeps it readable while the program runs.
- A target restricts where an annotation may sit. The TYPE target allows classes.
- getAnnotation reads an annotation back from a Class object.
- isAnnotationPresent answers false for a class without the annotation, and getAnnotation returns null there.
- SOURCE and CLASS retention are gone by runtime. Only RUNTIME annotations can be read back.
In this example, two classes carry the Info annotation and one class carries none. The program walks a fixed array of Class objects and reads the annotation from each one. Annotated classes print their author and version, and the unannotated class prints no info.
Note
An annotation does nothing on its own. A program or a tool must read it and act on its values.
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
Which retention must an annotation have so reflection can read it while the program runs?