All topics
library
intermediate

Annotations & Custom Annotations

Understand built-in annotations, create custom ones, and know the retention policies.

An annotation attaches metadata to code. It changes nothing by itself; something has to read it.

Annotations = sticky notes on your code. Some notes are for the compiler (removed after reading), others stay attached forever (RUNTIME) for frameworks to read at startup.

Key Concepts

1
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface Retry {
      int times() default 3;
      long delayMs() default 100;
    }
2
    @Retry(times = 5)
    void callPaymentApi() { ... }
3
Retention decides whether it survives, and this is the setting people get wrong:
4
    SOURCE    discarded after compiling   @Override, @SuppressWarnings
    CLASS     in the class file, not readable at runtime   (the default)
    RUNTIME   readable by reflection      Spring, JPA, Jackson
5
CLASS is the default, so an annotation you forgot to mark RUNTIME is invisible to reflection and your framework silently ignores it.
CLASSRUNTIME
6
Reading one at runtime.
    Retry r = method.getAnnotation(Retry.class);
    if (r != null) { for (int i = 0; i < r.times(); i++) { ... } }
7
@Target limits where it can appear — TYPE, METHOD, FIELD, PARAMETER, CONSTRUCTOR. Omit it and the annotation is allowed everywhere, which makes misuse compile.
@TargetTYPEMETHODFIELDPARAMETER
8
The other meta-annotations.
    @Documented   appears in Javadoc
    @Inherited    a subclass inherits it from its superclass
    @Repeatable   may be applied more than once to one element
9
The built-in ones worth knowing.
    @Override            the compiler checks you really are overriding
    @Deprecated          warns callers; pair it with @deprecated Javadoc
    @SuppressWarnings    silences a specific warning, narrowest scope possible
    @FunctionalInterface the compiler checks for exactly one abstract method
    @SafeVarargs         suppresses the generic varargs warning
10
Elements look like methods but are constants. Only primitives, String, Class, enums, annotations and arrays of those are allowed — so you cannot pass an arbitrary object.
StringClass
11
A single element named value can be set positionally: @Retry(5) rather than @Retry(value = 5).
value@Retry(5)@Retry(value = 5)
12
What the interviewer is probing.1. "Your custom annotation is invisible to reflection at runtime. Why?" Probing: retention, which is the usual cause. Stalls: "Reflection must be broken." Moves up: the default retention is CLASS, so it is in the class file but not readable at runtime; it needs RetentionPolicy.RUNTIME.
13
2. "What are the three retention policies and when would you use each?" Probing: whether you know what survives where. Stalls: "There is only runtime." Moves up: SOURCE for compiler-only checks like @Override, CLASS when bytecode tools need it, RUNTIME when a framework reads it reflectively.
14
3. "What types can an annotation element be?" Probing: the constant restriction. Stalls: "Anything." Moves up: primitives, String, Class, enums, annotations and arrays of those — all compile-time constants, so you cannot pass an arbitrary object.
15
4. "What does @Inherited actually do?" Probing: a commonly misread meta-annotation. Stalls: "Subclasses inherit it." Moves up: only class-level annotations are inherited by subclasses; it does nothing for methods or interfaces.