Skip to content
Preview · sample content · Explore all pages

Java annotations: retention and explicit processing

Last updated: 28 Sept 20263 min read
tutorial
IntermediateBy AITrove Editorial

An annotation attaches structured metadata to a declaration or type use; its effect depends on a compiler, tool, or runtime reader that interprets it.

Java 8+. Use a JDK that supports this release.

Metadata is not execution

A marker named Audited does not create an audit log. The program must read that marker and perform whatever action the application requires. The sample reads a service label, prints it, and stops; it deliberately contains no implicit interception machinery.

Retention controls how long the metadata survives. SOURCE metadata is unavailable after compilation. CLASS metadata is stored in class files but is not exposed as a runtime annotation through ordinary reflection. RUNTIME lets this program read the annotation while it runs.

Target limits legal placements. A type-level service marker should not accidentally be placed on a local variable and then silently ignored by a reader that only checks classes.

Define missing metadata behavior

getAnnotation may return null. Decide whether absence is allowed, defaults to another policy, or rejects registration. The sample uses an explicit unlabelled state rather than dereferencing a missing annotation.

Annotation values describe metadata; they cannot carry arbitrary mutable service objects. Keep operational state outside the annotation. If a value names a handler class, instantiating and validating that handler is a separate step.

Annotation processing during compilation and reflection at runtime are different mechanisms. A compile-time generator can create source files without the runtime retaining its marker. This lesson uses the runtime case only.

Working program

Java
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

public class ServiceLabels {
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    @interface ServiceLabel { String value(); }
    @ServiceLabel("shipment-index")
    static final class ShipmentIndex { }
    public static void main(String[] args) {
        ServiceLabel label = ShipmentIndex.class.getAnnotation(ServiceLabel.class);
        System.out.println(label == null ? "unlabelled" : label.value());
    }
}

Output

Output
shipment-index

Cost and design choices

One annotation lookup does not scan every object instance. Processing a registry of n service classes still requires work for those n classes and any generated registrations. Cache a validated registry rather than repeating inspection per request.

The marker does not establish authorization, a transaction, or a thread-safety guarantee. Such behavior requires tested code that owns those operations.

Common Mistakes

  • Do not expect a marker to execute behavior by itself.
  • Do not use CLASS retention when the reader requires runtime reflection.
  • Do not assume annotation inheritance applies to every placement.
java
annotations
Storage details