Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce unified support for declaring and looking up annotation attribute aliases [SPR-11512] #16137

Closed
spring-issuemaster opened this issue Mar 4, 2014 · 2 comments

Comments

Projects
None yet
2 participants
@spring-issuemaster
Copy link
Collaborator

commented Mar 4, 2014

Sam Brannen opened SPR-11512 and commented

Status Quo

Limited support for annotation attribute aliases already exists in the Spring Framework but is scattered across various modules. Currently, the following annotations are known to support aliases:

  • @ManagedResource
  • @ActiveProfiles
  • @ContextConfiguration
  • @Sql
  • @TestExecutionListeners
  • @TestPropertySource
  • @ControllerAdvice

Goal

The goal of this issue is to introduce unified support for declaring and looking up annotation attribute aliases (within a given annotation).


Deliverables

All annotations introduced in conjunction with this issue must reside in the org.springframework.core.annotation package.

  1. Introduce an annotation that can be declared on annotation attributes to indicate that the given attribute is an alias for another attribute of the same type within the same annotation class.
    • Proposed name: @AliasFor
  2. Consider introducing another annotation to be used on the aliased attribute itself in order to provide a two-way link between all such aliases.
    • Proposed name: @AliasedBy
  3. Extract code from the TestContext framework that is responsible for handling the look-up of annotation aliases and incorporate this code in a generic fashion in AnnotationUtils and AnnotatedElementUtils as appropriate.
    • This new look-up mechanism must be based on the annotation introduced in deliverable #1.
    • If multiple values for an aliased attribute are present in a declared annotation, an AnnotationConfigurationException must be thrown indicating that only one attribute for an aliased attribute may be specified in a concrete instance of the given annotation.
    • See also the current implementations for attribute aliases related to @ControllerAdvice and @ManagedResource.
  4. Migrate all existing code that supports attribute aliases to use this new mechanism.

Example: Modified @ContextConfiguration Declaration

The following demonstrates how @ContextConfiguration could be rewritten to take advantage of the functionality proposed by this issue.

public @interface ContextConfiguration {

    @AliasedBy("locations")
    String[] value() default {};

    @AliasFor("value")
    String[] locations() default {};

    // ...
}

Affects: 4.0 GA

Issue Links:

  • #16901 Custom @RequestMapping annotations ("is depended on by")
  • #16140 Document Spring Annotation Programming Model in the Wiki ("is depended on by")
  • #16020 Introduce aliases for 'value' annotation attributes ("is depended on by")
  • #17656 Implement toString() for synthesized annotations ("is depended on by")
  • #17657 Implement equals() for synthesized annotations ("is depended on by")
  • #17658 Implement hashCode() for synthesized annotations ("is depended on by")
  • #17879 Introduce 'value' alias for 'attribute' in @AliasFor ("is depended on by")
  • #17649 SynthesizedAnnotation must be public
  • #16138 Introduce support for explicit annotation attribute overrides
  • #17659 Introduce support for synthesizing AnnotationAttributes into an annotation
  • #16020 Introduce aliases for 'value' annotation attributes
@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented May 14, 2015

Sam Brannen commented

Current development work can be seen in my #16137 feature branch on GitHub.

Feel free to comment.

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented May 21, 2015

Sam Brannen commented

Implemented as described in the comments for GitHub commit ca66e07:

Support annotation attribute aliases and overrides via @AliasFor

This commit introduces first-class support for aliases for annotation attributes. Specifically, this commit introduces a new @AliasFor annotation that can be used to declare a pair of aliased attributes within a single annotation or an alias from an attribute in a custom composed annotation to an attribute in a meta-annotation.

To support @AliasFor within annotation instances, AnnotationUtils has been overhauled to "synthesize" any annotations returned by "get" and "find" searches. A SynthesizedAnnotation is an annotation that is wrapped in a JDK dynamic proxy which provides run-time support for @AliasFor semantics. SynthesizedAnnotationInvocationHandler is the actual handler behind the proxy.

In addition, the contract for @AliasFor is fully validated, and an AnnotationConfigurationException is thrown in case invalid configuration is detected.

For example, @ContextConfiguration from the spring-test module is now declared as follows:

public @interface ContextConfiguration {

    @AliasFor(attribute = "locations")
    String[] value() default {};

    @AliasFor(attribute = "value")
    String[] locations() default {};

    // ...
}

The following annotations and their related support classes have been
modified to use @AliasFor.

  • @ManagedResource
  • @ContextConfiguration
  • @ActiveProfiles
  • @TestExecutionListeners
  • @TestPropertySource
  • @Sql
  • @ControllerAdvice
  • @RequestMapping

Similarly, support for AnnotationAttributes has been reworked to support @AliasFor as well. This allows for fine-grained control over exactly which attributes are overridden within an annotation hierarchy. In fact, it is now possible to declare an alias for the value attribute of a meta-annotation.

For example, given the revised declaration of @ContextConfiguration above, one can now develop a composed annotation with a custom attribute override as follows.

@ContextConfiguration
public @interface MyTestConfig {

    @AliasFor(annotation = ContextConfiguration.class, attribute = "locations")
    String[] xmlFiles();

    // ...
}

Consequently, the following are functionally equivalent.

  • @MyTestConfig(xmlFiles = "test.xml")
  • @ContextConfiguration("test.xml")
  • @ContextConfiguration(locations = "test.xml")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.