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

Support implicit attribute aliases with @AliasFor [SPR-13345] #17929

Closed
1 of 2 tasks
spring-projects-issues opened this issue Aug 12, 2015 · 2 comments
Closed
1 of 2 tasks
Assignees
Labels
in: core Issues in core modules (aop, beans, core, context, expression) type: enhancement A general enhancement
Milestone

Comments

@spring-projects-issues
Copy link
Collaborator

spring-projects-issues commented Aug 12, 2015

Sam Brannen opened SPR-13345 and commented

Status Quo

Spring Framework 4.2 introduced support for explicit annotation attribute overrides in meta-annotations via @AliasFor.

For example, the following @SingleAliasConfig works as expected. xmlFiles functions as an attribute override for locations in @ContextConfiguration.

@ContextConfiguration
public @interface SingleAliasConfig {

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

   // ...
}

However, the following @ImplicitAliasesConfig does not work as expected. One would intuitively expect that any one of xmlFiles, groovyScripts, or value could be used as an attribute override for locations in @ContextConfiguration, but at runtime, we don't actually know which one of the aliases will be ultimately used. In other words, one would expect xmlFiles, groovyScripts, and value to be considered implicit aliases for each other.

The reason is that the merge algorithm in MergedAnnotationAttributesProcessor in AnnotatedElementUtils overwrites previous aliased values with subsequent aliased values, thereby letting the last one win -- which happens silently and is unintuitive.

@ContextConfiguration
public @interface ImplicitAliasesConfig {

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

   @AliasFor(annotation = ContextConfiguration.class, attribute = "locations")
   String[] groovyScripts() default {};

   @AliasFor(annotation = ContextConfiguration.class, attribute = "locations")
   String[] value() default {};

   // ...
}

Similarly, the following declaration of transitive implicit aliases is not supported: xml and groovy will not be considered as implicit aliases for each other even though they override attributes in @ImplicitAliasesConfig which are implicit aliases for each other.

@ImplicitAliasesConfig
public @interface TransitiveImplicitAliasesConfig {

   @AliasFor(annotation = ImplicitAliasesConfig.class, attribute = "xmlFiles")
   String[] xml() default {};

   @AliasFor(annotation = ImplicitAliasesConfig.class, attribute = "groovyScripts")
   String[] groovy() default {};

   // ...
}

Deliverables

  1. Support implicit aliases configured via @AliasFor for the same attribute in a meta-annotation.
  2. Support transitive implicit aliases.

Affects: 4.2 GA

Reference URL: spring-projects/spring-boot#3635

Issue Links:

Referenced from: commits 2a6716d, d40a35b, 3eacb83

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented Aug 15, 2015

Sam Brannen commented

The work for this issue is currently being developed on my #17929 branch. Feel free to follow along and/or comment.

@spring-projects-issues
Copy link
Collaborator Author

Sam Brannen commented

Completed in GitHub commit d40a35b:

Support implicit attribute aliases with @AliasFor

Spring Framework 4.2 introduced support for aliases between annotation attributes that fall into the following two categories.

  1. Alias pairs: two attributes in the same annotation that use @AliasFor to declare that they are explicit aliases for each other.
  2. Meta-annotation attribute overrides: an attribute in one annotation uses @AliasFor to declare that it is an explicit override of an attribute in a meta-annotation.

However, the existing functionality fails to support the case where two attributes in the same annotation both use @AliasFor to declare that they are both explicit overrides of the same attribute in the same meta-annotation. In such scenarios, one would intuitively assume that two such attributes would be treated as "implicit" aliases for each other, analogous to the existing support for explicit alias pairs. Furthermore, an annotation may potentially declare multiple aliases that are effectively a set of implicit aliases for each other.

This commit introduces support for implicit aliases configured via @AliasFor through an extensive overhaul of the support for alias lookups, validation, etc. Specifically, this commit includes the following.

  • Introduced isAnnotationMetaPresent() in AnnotationUtils.
  • Introduced private AliasDescriptor class in AnnotationUtils in order to encapsulate the parsing, validation, and comparison of both explicit and implicit aliases configured via @AliasFor.
  • Switched from single values for alias names to lists of alias names.
  • Renamed getAliasedAttributeName() to getAliasedAttributeNames() in AnnotationUtils.
  • Converted alias map to contain lists of aliases in AnnotationUtils.
  • Refactored the following to support multiple implicit aliases: getRequiredAttributeWithAlias() in AnnotationAttributes, AbstractAliasAwareAnnotationAttributeExtractor, MapAnnotationAttributeExtractor, MergedAnnotationAttributesProcessor in AnnotatedElementUtils, and postProcessAnnotationAttributes() in AnnotationUtils.
  • Introduced numerous tests for implicit alias support, including AbstractAliasAwareAnnotationAttributeExtractorTestCase, DefaultAnnotationAttributeExtractorTests, and MapAnnotationAttributeExtractorTests.
  • Updated Javadoc in @AliasFor regarding implicit aliases and in AnnotationUtils regarding "meta-present".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: core Issues in core modules (aop, beans, core, context, expression) type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

2 participants