BackendBench
Coffee

Unravel › Java concepts › OOP and types

Java language

Custom annotations

An annotation is a label you attach to code (@Deprecated, @Test).

🔎 Unravel this example

At a glance

Mental model

Sticky notes on code.

What happens, in order
  1. 1@Retention(RUNTIME) @Target(METHOD) public @interface Audited { String value() default ""; } defines the label, where it may go, and how long it stays
  2. 2RetentionPolicy.SOURCE notes vanish after compiling (@Override), CLASS stay in the file, RUNTIME notes can be read by reflection, which is what frameworks need
  3. 3A reader finds them with reflection: method.getAnnotation(Audited.class)Frameworks like Spring wrap the annotated bean in a proxy that does the extra work.
  4. 4Elements look like methods with optional defaults; the only allowed types are primitives, String, Class, enums, annotations and arrays of those
Remember
Watch out
Forgetting @Retention(RUNTIME) so reflection sees nothingExpecting an annotation to change behaviour without any processorPutting it on a target the @Target does not allow
Example (highlighted lines explain it)
import java.lang.annotation.*;@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)public @interface Audited {  String value() default "";  int level() default 1;}
  1. line 2 uses Retention, the core of Custom annotations
  2. line 3 uses Target, the core of Custom annotations
Read the full explanation (about 1 min)

An annotation is a label you attach to code (@Deprecated, @Test). You can define your own with @interface; something else (the compiler, a framework, your own reflection code) then reads the labels.

A mental model

Sticky notes on code. The note itself does nothing: it only matters because somebody (a tool) walks around reading the notes and acting on them.

How it works

@Retention(RUNTIME) @Target(METHOD) public @interface Audited { String value() default ""; } defines the label, where it may go, and how long it stays.

RetentionPolicy.SOURCE notes vanish after compiling (@Override), CLASS stay in the file, RUNTIME notes can be read by reflection, which is what frameworks need.

A reader finds them with reflection: method.getAnnotation(Audited.class). Frameworks like Spring wrap the annotated bean in a proxy that does the extra work.

Elements look like methods with optional defaults; the only allowed types are primitives, String, Class, enums, annotations and arrays of those.

Going deeper

An annotation that nothing reads is only documentation. If a custom annotation seems to "not work", check the retention (must be RUNTIME), the target and whether the processing code runs for that object (a Spring proxy is not applied to calls from inside the same class).

@SuppressWarnings and @Deprecated are also annotations. Use @Deprecated(since = "2.0", forRemoval = true) to give callers a clear message.

Under the hood

RUNTIME annotations are stored in the RuntimeVisibleAnnotations attribute and the JVM creates a proxy object implementing your annotation interface when you read one. Annotation processors run at compile time and can generate code (Lombok, MapStruct).

Common mistakes

  • Forgetting @Retention(RUNTIME) so reflection sees nothing.
  • Expecting an annotation to change behaviour without any processor.
  • Putting it on a target the @Target does not allow.

How Unravel recognises it

When you paste code, Unravel looks for these signs of custom annotations. Spotting them yourself is a good habit when you read unfamiliar code:

Part of a learning path

Related concepts

Builds on this

Frequently asked questions

What is Custom annotations?

An annotation is a label you attach to code (@Deprecated, @Test). You can define your own with @interface; something else (the compiler, a framework, your own reflection code) then reads the labels.

What are the most common mistakes with Custom annotations?

Forgetting @Retention(RUNTIME) so reflection sees nothing. Expecting an annotation to change behaviour without any processor. Putting it on a target the @Target does not allow.

How can I see Custom annotations in real code?

Paste your own Java into Unravel and it will point out where custom annotations appears, explain how it works at the detail level you choose, and draw the flow of the code around it.