Platform & Advanced APIs
Annotations
- Declare with
@interface; elements look like methods with optional defaults @Retention(RUNTIME)for reflection-read;SOURCE/CLASSfor compile-time tools@Targetrestricts placement (TYPE, METHOD, FIELD, PARAMETER, TYPE_USE…)- Standard set:
@Override,@Deprecated(since, forRemoval),@SuppressWarnings,@FunctionalInterface,@SafeVarargs - Frameworks run on annotations: DI (
@Inject), JPA (@Entity), JUnit (@Test), Jackson (@JsonProperty) - Prefer annotations to naming patterns (EJ 39); always use
@Override(EJ 40)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Scheduled {
String cron();
boolean enabled() default true;
}
// The processor — nothing happens without it:
for (Method m : jobClass.getDeclaredMethods()) {
Scheduled s = m.getAnnotation(Scheduled.class);
if (s != null && s.enabled())
scheduler.register(s.cron(), () -> invoke(m));
}Element types are limited: primitives, String, Class, enums, annotations, and arrays thereof — values must be compile-time constants. Meta-annotations shape behavior: @Inherited (subclasses see class-level annotations), @Repeatable (multiple @Scheduled on one method), @Documented (appears in Javadoc). TYPE_USE targets let annotations decorate types (List<@NonNull String>) — the basis of pluggable null-checking frameworks.
Compile-time processing (Core Java II ch. 8): annotation processors registered with javac generate code from annotations — how Lombok, Dagger, MapStruct, and records-like libraries work without runtime reflection cost. Processors can only create new files, not modify existing ones (Lombok famously cheats). Runtime processing via Reflection is simpler and dominant in frameworks like Spring.