Skip to content
Back to skills

Java Annotations

ASecurity

Annotations as metadata that only means something if code reads it: retention policies and what each one costs, targets and where an annotation on a record component actually lands, @Inherited and its limits, marker interfaces versus marker annotations, @Override as a correctness check rather than decoration, and the gap between annotating something and enforcing it. Use when defining a custom annotation, when an annotation appears to have no effect, when validation or security annotations ar...

  • 2 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 19, 2026
developmentrustjavaexpressspringdebuggingapisecuritydocumentation

Works with

  • api

Security analysis

A100/100

Pro scans all 4 files and shows the line behind each finding

Scanned September 29, 2026

npx -y skills add robsonkades/agent-skills --skill java-annotations --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Java Annotations?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Java Annotations
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/robsonkades-java-annotations/badge)](https://www.skillsdirectory.com/skills/robsonkades-java-annotations)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: java-annotations
description: >
  Annotations as metadata that only means something if code reads it: retention policies and
  what each one costs, targets and where an annotation on a record component actually lands,
  @Inherited and its limits, marker interfaces versus marker annotations, @Override as a
  correctness check rather than decoration, and the gap between annotating something and
  enforcing it. Use when defining a custom annotation, when an annotation appears to have no
  effect, when validation or security annotations are trusted without a validator or a proxy
  invoking them, when @Override is missing on an override, when a naming convention encodes
  behaviour that an annotation should carry, when annotation scanning slows startup or
  breaks under native image, or when deciding between a marker interface and a marker
  annotation. Does not cover nullability annotation contracts (java-null-safety), reflective
  access mechanics (java-reflection-and-method-handles), or the enum type itself
  (java-enums).
---

# Java Annotations

## Purpose

Keep metadata honest: an annotation changes nothing by itself, so every annotation in a
codebase must have an identifiable reader — a compiler check, an annotation processor, a
runtime framework — or it is a comment with a compiler-checked spelling. Two failure modes:
the annotation that is believed to be enforcing something it is not (a `@NotNull` with no
validator on the path, a `@Transactional` bypassed by self-invocation), and the naming
convention or magic string doing a job an annotation would do with compile-time checking.

## Workflow

Match the requested action: a review reports findings; diagnosis establishes a cause or the
next discriminating check; implementation changes the annotation or consumer only when requested.
Inspect the annotation definition, actual reader/call sites, build configuration and relevant tests
before asking for missing context. Treat a documented contract as stronger evidence of intended
behavior than an isolated usage pattern; state consequential assumptions when they disagree.

0. **Establish compatibility.** Inspect compiler release/toolchain, processor configuration,
   resolved framework versions and runtime. Language references and sketches here use Java 17;
   records require Java 16+ without preview, and
   `Deprecated.since`/`forRemoval` require Java 9+. Adapt to the project without upgrading it,
   enabling preview or adding dependencies implicitly. If configuration is missing, keep
   enforcement diagnoses conditional and name the evidence needed.
1. **Name the consumer before defining the annotation.** It may be the compiler, processor,
   framework, static-analysis tool, documentation generator or a human-facing API contract. If no
   consumer benefits from structured metadata, Javadoc is usually clearer. Keep adequate direct
   code or configuration; adding metadata or a processor needs a concrete consumer benefit.
2. **Pick retention from the reader and artifact boundary.** `SOURCE` suffices when every required
   reader sees the annotated source in that compilation. A later build inspecting compiled
   dependencies needs retained metadata too: `CLASS` can serve bytecode tools and processors
   inspecting binary declarations; ordinary runtime reflection needs `RUNTIME`. Verify the actual
   consumer instead of choosing retention from "build time" versus "runtime" alone.
3. **Constrain the targets.** `@Target` restricts where it can be applied; without it, an
   annotation is legal in places the reader never looks, which is how "the annotation does
   nothing here" bugs happen.
4. **Verify the consumer's promised result.** For enforcement, exercise valid and invalid input
   through the actual path and assert acceptance/rejection. For documentation or generation,
   check the produced output and excluded cases; no runtime enforcement is implied.
5. **Check relevant deployment boundaries** — proxying, native image and modules when the
   actual consumer uses them. Reuse adequate existing tests and evidence; metadata visibility
   is a different check from discovery, invocation and enforcement.

## Rules

- Use `@Override` on every method that overrides or implements one. It is the cheapest
  correctness check the language offers, and the one it catches is the expensive one: an
  `equals(MyType other)` that overloads instead of overriding, so the collection calls
  `Object.equals` and identity semantics apply. Interface implementations included — it is
  allowed there and catches the same drift when the interface changes.
- Prefer an annotation to a naming pattern when the tool/API supports metadata (`@Test` over
  `testFoo`, `@Deprecated` plus migration Javadoc). The compiler checks annotation syntax and
  target, while the annotation's processor/framework still owns semantic validation.
- Prefer a marker **interface** when the marked thing is a type and something should be checked
  at compile time: an interface defines a type, so it can be a parameter or return type, and
  the compiler enforces it at every use. Prefer a marker **annotation** when the target is not
  a type (methods, fields, parameters, packages, modules), when the marking must be added later
  without touching the type hierarchy, or when the marker may gain parameters.
- Give every annotation an explicit `@Retention` and `@Target`. The default retention is
  `CLASS`, so a hand-written annotation is invisible to ordinary runtime reflection unless
  retention is changed. A framework reading class-file metadata directly has a different contract.
- `@Inherited` applies only to annotations on **classes**, and only along the superclass chain.
  It does not make an annotation inherited from an interface, and it does not apply to methods
  or fields. Framework meta-annotation mechanisms (Spring's `@AliasFor`, `MergedAnnotations`)
  implement their own richer rules — those are the framework's semantics, not the language's.
- An annotation on a **record component** follows target and declaration rules, including
  `RECORD_COMPONENT` and `TYPE_USE`. Explicit accessors and normal canonical constructors
  differ from generated members; read the retention reference before changing either.
  A validation annotation that targets only
  `FIELD` will not be seen by a framework reading the constructor parameters. State the
  targets, and test that the constraint actually fires.
- Annotations do not validate anything. Jakarta Bean Validation constraints run only when a
  `Validator` is invoked — by the framework at a `@Valid` parameter, or by your code. A DTO
  covered in `@NotBlank` that is deserialised and used without validation is unvalidated
  input; java-defensive-programming covers where the check belongs.
- Proxy-based annotations (`@Transactional`, `@Cacheable`, `@Retryable`, `@Async` and equivalents)
  depend on the configured advice mechanism. In ordinary Spring proxy mode, self-invocation and
  private methods bypass advice; final classes/methods block subclass proxies but interface-based
  proxies differ. AspectJ weaving and programmatic APIs have other semantics. Test the actual
  call path; framework-coupling-and-independence covers making it visible.
- `RUNTIME` metadata does not itself force whole-classpath scanning or defeat AOT. Startup cost
  depends on framework indexing, scan scope and caching; native-image reachability depends on what
  build-time analysis can discover and supplied metadata. Prefer annotation processing or
  build-time generation when it provides equivalent semantics and its build/debugging cost is
  acceptable. On JDK 23+, command-line `javac` runs processors only when annotation processing is
  explicitly configured (for example `--processor-path`, `-processor`, or `-proc:full`); ensure
  the build tool declares processors rather than relying on classpath discovery.
- Do not put secrets in annotation elements. Explicit values are restricted to
  annotation-compatible constants/types and may be visible through bytecode/reflection.
  A fixed literal may be a property key or expression that the consumer resolves from external
  configuration; verify that consumer and its refresh lifecycle. Changing an annotation default
  can affect already compiled uses that omitted the element; review this as API behavior.

- For repeatable annotations, inspect both the repeated annotation and its container: retention,
  target and inheritance must be compatible. For `TYPE_USE`, decide whether the consumer reads
  declaration annotations or type annotations; they occupy different class-file/reflection APIs.
  Occurrences only on type uses do not trigger JSR 269 processor matching by annotation name.
  Check processor invocation and type traversal before trusting a compile-time checker; the
  retention reference covers selection and coexistence with other processors.
- Deprecate with `@Deprecated(since = "…", forRemoval = …)` plus `@deprecated` Javadoc saying
  what to use instead. `forRemoval = true` turns usage warnings into a stronger signal and is
  part of the API contract — see java-api-design.

## Deliverable

Identify the reader and call path, observed metadata/configuration, consequence, smallest
correction and a check that confirms it. Distinguish static evidence from executed rejection
tests. For a new annotation, supply its retention/target contract and consumer integration
with positive and negative checks. Annotation presence or reflection visibility alone does
not demonstrate enforcement.

Stop when the requested decision is supported by the reader/target contract and appropriate
consumer checks, or report precisely which unavailable evidence prevents that conclusion.
For a neighboring concern, pass the annotation definition, reader/call path, project versions and
observed failure to its named specialist. If unavailable, retain the metadata findings and identify
the remaining check rather than inventing a framework, nullness or native-image guarantee.

## References

- [Retention, targets and processing](references/retention-targets-and-processing.md) — read
  when defining an annotation, when one appears to have no effect, or when choosing between
  runtime reflection, an annotation processor and build-time generation.
- [Markers, custom annotations and enforcement](references/markers-and-custom-annotations.md)
  — read when choosing between a marker interface and a marker annotation, when designing an
  annotation that must be enforced, or when annotation-driven behaviour is silently not
  applying.

Files in this skill

  • SKILL.md8.9 KB
  • references/markers-and-custom-annotations.md9.4 KB
  • references/retention-targets-and-processing.md10.4 KB
  • skill.yaml2 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…