Annotation Interface Retainable


@Documented @Retention(RUNTIME) @Target(ANNOTATION_TYPE) public @interface Retainable

Marks an annotation as retainable: every annotation that composes it keeps the composed occurrence on its own AnnotationValue, in the AnnotationMetadata of every element the composing annotation is applied to, in addition to flattening it into the element's stereotypes.

AnnotationMetadata indexes stereotypes by name, which loses the association between an individual stereotype occurrence and the annotation that introduced it: two annotations that each compose a repeatable annotation contribute two indistinguishable occurrences. A retainable annotation is also kept as a tree under the annotation composing it, with member overrides declared through io.micronaut.context.annotation.AliasFor already applied, and is read back with AnnotationValue.getStereotypes(). An annotation is retainable when this marker is present anywhere in its own stereotypes, so a framework annotation marks its whole family at once, and a retained occurrence keeps its own retainable stereotypes in turn:

@Retainable
@interface Constraint {
}

@Constraint
@interface Size {
    int min() default 0;
}

@Size(min = 5)
@interface Username {
    @AliasFor(annotation = Size.class, member = "min")
    int min() default 5;
}

// for an element annotated @Username(min = 3)
metadata.getAnnotation(Username.class).getStereotypes(); // [ @Size(min = 3) ]

Retention costs generated code proportional to the number of retainable occurrences at every use site, so it is opt-in and has no cost for annotations that compose nothing retainable. The marker itself is never retained.

Since:
5.2.0