Closed
Description
Sam Brannen opened SPR-11513 and commented
Status Quo
The Spring Framework provides support for meta-annotation attribute overrides in custom composed annotations. However, as of Spring 4.0, such overrides are only supported for attributes with names other than value
, and the overriding attribute must have the exact same name and type as the attribute it overrides.
If multiple meta-annotations are used to compose the custom annotation, and if these meta-annotations declare attributes of the same name and type (e.g., String name() default "";
), then there is a conflict. In such scenarios:
- It is impossible to know which attribute is being overridden.
- The attribute in the composed annotation effectively overrides all attributes of the same name and type within the annotation hierarchy.
- It is impossible to specify different overriding values for attributes with the same name.
Furthermore, it is currently impossible to override a value
attribute from a meta-annotation.
Deliverables
- Introduce a new annotation that indicates the name of the attribute being overridden as well as the annotation type.
- See proposals below.
- An alternative would be to reuse the
@AliasFor
annotation introduced in Introduce unified support for declaring and looking up annotation attribute aliases [SPR-11512] #16137. - See also the @OverridesAttribute annotation from the Java Bean Validation spec.
- Revise the search algorithms in
AnnotationUtils
andAnnotatedElementUtils
so that they honor this new annotation.
Proposals for Annotation Name
@OverridesMeta
@MetaAnnotationAttribute
@AnnotationAttributeMapping
Example: Overriding Multiple value
Attributes
The following example demonstrates how to:
- Override a
value
attribute - Override attributes from multiple meta-annotations with the same attribute name (in this case
value
)
@Async
@Transactional
public @interface AsyncTransactional {
/**
* Qualifier for the name of the TaskExecutor.
*/
@OverridesMeta(annotation = Async.class, attribute = "value")
String taskExecutor();
/**
* Qualifier for the name of the PlatformTransactionManager.
*/
@OverridesMeta(annotation = Transactional.class, attribute = "value")
String transactionManager();
}
@AsyncTransactional(taskExecutor = "userTaskExecutor", transactionManager = "txMgr")
@Service
public class UserService {
// ...
}
Example: Overriding Attribute With Custom Name
@Scope("request")
@Component
public @interface RequestScopedWebComponent {
/**
* Proxy mode.
*/
@OverridesMeta(annotation = Scope.class, attribute = "proxyMode")
ScopedProxyMode mode() default ScopedProxyMode.TARGET_CLASS;
}
@RequestScopedWebComponent(mode = ScopedProxyMode.INTERFACES)
public class ProductionWebComponent implements WebComponent {
// ...
}
Affects: 4.0 GA
Issue Links:
- Document Spring Annotation Programming Model in the Wiki [SPR-11515] #16140 Document Spring Annotation Programming Model in the Wiki ("is depended on by")
- Introduce unified support for declaring and looking up annotation attribute aliases [SPR-11512] #16137 Introduce unified support for declaring and looking up annotation attribute aliases
- Introduce a comprehensive programming model for meta-annotation support [SPR-11511] #16136 Introduce a comprehensive programming model for meta-annotation support
- SynthesizedAnnotation must be public [SPR-13057] #17649 SynthesizedAnnotation must be public
- Introduce support for synthesizing AnnotationAttributes into an annotation [SPR-13067] #17659 Introduce support for synthesizing AnnotationAttributes into an annotation
- Introduce aliases for 'value' annotation attributes [SPR-11393] #16020 Introduce aliases for 'value' annotation attributes