Home/Learn/Java A–Z/Annotations

Annotations

Intermediate
OOP Deep Dive

Annotations 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.

BuiltinAnnotations.java
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).

CustomAnnotation.java
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.

AnnotationReflection.java
// 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 Aria
1

What is the difference between SOURCE, CLASS, and RUNTIME retention?

MediumAmazon
2

How does Spring use annotations like @Autowired internally?

MediumGoogle
3

What is an annotation processor and how does Lombok use it?

HardOracle
4

Why is @FunctionalInterface useful even though Java can infer it?

EasyMicrosoft
5

Can you annotate annotations? What meta-annotations are available?

MediumTCS

Ask Aria about Annotations

Your personal AI tutor — ask anything about this concept