Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

A repeatable annotation in Java allows the same annotation type to be applied more than once to a single program element. Introduced in Java SE 8, it provides syntactic sugar that eliminates the need to manually group multiple annotations of the same type within an array-based container annotation. Under the hood, the Java compiler automatically wraps the repeated annotations into a designated container annotation. To implement this, the architecture requires two distinct annotation interfaces: the Repeatable Annotation and the Container Annotation.

1. The Container Annotation

The container annotation must declare a value() element whose return type is an array of the repeatable annotation type.
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface Configs {
    Config[] value();
}

2. The Repeatable Annotation

The annotation to be repeated must be meta-annotated with @java.lang.annotation.Repeatable. The value passed to @Repeatable is the .class literal of the container annotation.
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Repeatable(Configs.class)
@Retention(RetentionPolicy.RUNTIME)
public @interface Config {
    String key();
    String value();
}

3. Application Syntax

Once linked via the @Repeatable meta-annotation, the compiler allows the annotation to be stacked directly on a target element.
@Config(key = "timeout", value = "5000")
@Config(key = "retries", value = "3")
public class NetworkClient {
    // Implementation
}
During compilation, the compiler transforms the above syntax into the legacy array format. The resulting bytecode is identical to: @Configs({@Config(key="timeout", value="5000"), @Config(key="retries", value="3")})

Reflection and Retrieval

Because the compiler wraps repeatable annotations inside the container annotation, Java 8 introduced the getAnnotationsByType() method in the Reflection API (java.lang.reflect.AnnotatedElement). This method automatically unpacks the container and returns an array of the repeated annotations.
Class<NetworkClient> clazz = NetworkClient.class;

// Unpacks the container and returns the individual annotations
Config[] configs = clazz.getAnnotationsByType(Config.class);

for (Config config : configs) {
    System.out.println(config.key() + " = " + config.value());
}
If you use the older getAnnotation(Config.class) method on an element with repeated annotations, it will return null because the element is technically annotated with the container (@Configs), not the individual @Config annotation.

Structural Constraints

To successfully compile a repeatable annotation, the Java compiler enforces strict rules regarding meta-annotations:
  • Target Compatibility: The @Target of the container annotation must be a subset of, or identical to, the @Target of the repeatable annotation. If the container annotation can be applied to a METHOD, the repeatable annotation must also be applicable to a METHOD.
  • Retention Compatibility: The @Retention policy of the container annotation must be equal to or broader than the retention policy of the repeatable annotation. You cannot have a RUNTIME repeatable annotation wrapped in a SOURCE container annotation.
  • Documented/Inherited: If the repeatable annotation is marked with @Documented or @Inherited, the container annotation must also be marked with the exact same meta-annotations to preserve expected behavior.
Master Java with Deep Grasping Methodology!Learn More