Custom Annotations
TL;DR
- You can create your own Custom Annotations using the
@interfacekeyword. - You must configure them with meta-annotations:
@Retention(when it’s available) and@Target(where it can be placed). - Custom annotations require a custom processing engine (usually via Reflection) to actually do anything.
Concept
Creating an annotation is like defining an interface. You can define properties (methods) that act as configuration values.
However, the annotation alone does nothing. You must write an engine that scans your classes at runtime (or compile-time).
For example, if you want an @Important annotation, you define it. Then you write a utility class that uses Reflection to find all methods marked with @Important and prints them to the console.
Crucial Meta-Annotations
@Retention: Determines if the annotation is thrown away by the compiler (SOURCE), kept in the .class file but ignored at runtime (CLASS), or loaded into the JVM memory so you can read it with Reflection (RUNTIME).@Target: Restricts where the annotation can be placed (e.g.,ElementType.METHOD,ElementType.TYPEfor classes).
Examples
import java.lang.annotation.*;
// 1. DEFINE THE ANNOTATION
@Retention(RetentionPolicy.RUNTIME) // Must be RUNTIME to use Reflection!
@Target(ElementType.METHOD) // Can only be put on methods
public @interface Retry {
int maxAttempts() default 3; // Define a property with a default value
}
// 2. USE THE ANNOTATION
public class NetworkService {
@Retry(maxAttempts = 5)
public void connectToDatabase() {
System.out.println("Connecting...");
}
}
// 3. PROCESS THE ANNOTATION (The Engine)
public class AnnotationProcessor {
public static void main(String[] args) throws Exception {
Method method = NetworkService.class.getMethod("connectToDatabase");
// Check if the annotation exists
if (method.isAnnotationPresent(Retry.class)) {
// Read the properties from the annotation
Retry retryConfig = method.getAnnotation(Retry.class);
System.out.println("Will retry " + retryConfig.maxAttempts() + " times.");
}
}
}
Interview Questions
Q: Why did your Custom Annotation return null when you checked for it at runtime?
A: Because you forgot to add @Retention(RetentionPolicy.RUNTIME) to the annotation definition. The default retention policy in Java is CLASS. This means the compiler puts the annotation in the .class file, but the JVM deletes it when loading the class into memory. Therefore, when your Reflection code asks for it at runtime, it’s already gone.
Q: Can an Annotation hold a complex Object (like a List or a custom class)?
A: No. Annotation properties are heavily restricted. They can only return:
- Primitives (
int,boolean, etc.) StringClass- Enums
- Other Annotations
- Arrays of the above (e.g.,
String[]).
You cannot return aList<String>or an instance of a normal Java Object.