library
intermediateAnnotations & 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, Jackson5
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 element9
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 warning10
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.