Annotations
IntermediateAnnotations add metadata to Java code elements, enabling frameworks like Spring, JPA, and JUnit to configure behaviour declaratively.
Overview
Annotations (@interface) attach metadata to classes, methods, fields, parameters, and other code elements. Built-in annotations (@Override, @Deprecated, @SuppressWarnings) serve compiler hints. Framework annotations (@Entity, @Autowired, @Test) drive entire frameworks. Custom annotations combined with annotation processors or reflection enable code generation, validation, and AOP. Understanding retention policies and targets is essential for writing effective annotations.
Built-in Annotations
@Override tells the compiler you intend to override a supertype method — it is a compile-time safety net. @Deprecated marks code as obsolete and causes IDE warnings. @SuppressWarnings silences specific compiler warnings. @FunctionalInterface ensures an interface has exactly one abstract method.
public class Animal {
public String sound() { return "..."; }
}
public class Dog extends Animal {
@Override // compile error if sound() doesn't exist in Animal
public String sound() { return "Woof"; }
@Deprecated(since = "2.0", forRemoval = true)
public void oldMethod() { /* will be removed */ }
@SuppressWarnings("unchecked")
public void uncheckedOp(Object obj) {
List<String> list = (List<String>) obj; // suppresses warning
}
}
@FunctionalInterface
interface Transformer<T, R> {
R transform(T input);
// adding a second abstract method here → compile error
}Custom Annotations
Define an annotation with @interface. Use meta-annotations to configure it: @Retention (when it is available), @Target (where it can be applied), @Documented (include in Javadoc), @Repeatable (allow multiple on same element).
Retention: SOURCE (discarded at compile time), CLASS (in bytecode, not loaded), RUNTIME (available via reflection).
import java.lang.annotation.*;
// Custom annotation definition
@Retention(RetentionPolicy.RUNTIME) // available at runtime
@Target({ElementType.METHOD, ElementType.TYPE})
@Documented
public @interface RateLimit {
int requestsPerMinute() default 60;
String message() default "Rate limit exceeded";
}
// Usage
@RateLimit(requestsPerMinute = 100)
public class UserController {
@RateLimit(requestsPerMinute = 10, message = "Too many login attempts")
public void login(String user, String pass) { /* ... */ }
@RateLimit // uses defaults
public void getProfile(String userId) { /* ... */ }
}Processing Annotations with Reflection
At runtime, use Class.getAnnotation(), Method.getAnnotation() to read annotation values. This is how frameworks like Spring read @Autowired, @RequestMapping, etc.
For compile-time processing (code generation), use the javax.annotation.processing.Processor API. Libraries like Lombok and MapStruct use this extensively.
// Read annotation at runtime via reflection
import java.lang.reflect.*;
Class<?> cls = UserController.class;
// Class-level annotation
RateLimit classLimit = cls.getAnnotation(RateLimit.class);
if (classLimit != null) {
System.out.println("Class limit: " + classLimit.requestsPerMinute());
}
// Method-level annotations
for (Method method : cls.getDeclaredMethods()) {
RateLimit limit = method.getAnnotation(RateLimit.class);
if (limit != null) {
System.out.printf("Method %s: %d req/min — %s%n",
method.getName(),
limit.requestsPerMinute(),
limit.message());
}
}Key Points to Remember
- @Override, @Deprecated, @SuppressWarnings, @FunctionalInterface are built-in compiler annotations.
- Define custom annotations with @interface; control scope with @Retention and @Target.
- RetentionPolicy.RUNTIME is required for runtime access via reflection.
- ElementType controls where an annotation can be applied (METHOD, TYPE, FIELD, etc.).
- Annotation processors (APT) run at compile time and can generate new source files.
Practice Annotations in the Playground
Run and modify code directly in your browser - no setup needed.
Interview Questions
Sign in to ask AriaWhat is the difference between SOURCE, CLASS, and RUNTIME retention?
How does Spring use annotations like @Autowired internally?
What is an annotation processor and how does Lombok use it?
Why is @FunctionalInterface useful even though Java can infer it?
Can you annotate annotations? What meta-annotations are available?
Ask Aria about Annotations
Your personal AI tutor — ask anything about this concept