A repeatable annotation lets one declaration carry several values of the same annotation type. getAnnotationsByType returns the contained values to runtime code.
Java repeatable annotations: read every declared routing label
Operational contract
The Label annotation names a container through @Repeatable; both definitions use runtime retention and the same METHOD target. The sample copies the reflected labels into an immutable list of route names. It rejects a method without labels rather than silently treating it as public. The order of labels is the declared container order, but callers should not use annotation order as a priority rule unless that rule is explicit and tested. Route labels are configuration metadata, not proof that the request is allowed to access a route.
Failure case
A dispatch method carries labels 'depot-47' and 'depot-82'. A router reads both, then applies its own authorization and conflict rules. Reading only getAnnotation(Label.class) may miss the intended repeated values when a container is present.
Java code
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
public class DispatchLabelReader {
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Repeatable(Labels.class)
public @interface Label { String value(); }
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Labels { Label[] value(); }
@Label("depot-47") @Label("depot-82")
public void dispatch() { }
public static List<String> labels(Method method) {
Label[] declared = method.getAnnotationsByType(Label.class);
if (declared.length == 0) throw new IllegalArgumentException("No route labels");
List<String> names = new ArrayList<>(declared.length);
for (Label label : declared) names.add(label.value());
return List.copyOf(names);
}
}Performance and ownership cost
Reflection returns R annotation values, and copying their strings costs O(R) time and O(R) list storage. Annotation lookups in a hot route should be resolved once at startup, while per-request authorization still uses current security state.
Common Mistakes
- Do not query a repeated annotation as if only one instance can exist.
- Do not give the container a different target or retention contract.
- Do not treat labels as access-control decisions.
Connected lessons
- Java annotation retention: expose metadata without pretending it enforces policy
- Java annotations: retention and explicit processing
- Java reflection: inspect types without breaking contracts
- Java enum constant bodies: keep each fee rule with its tier
- Java generics and language contracts quiz
- Advanced Java
