Skip to content

Support unidirectional @AliasFor attribute mapping within an annotation #23834

@lucasoares

Description

@lucasoares

Original Title

Issue with AliasFor annotation upgrading from 5.1.7 to 5.2.0

Overview

I'm trying to update Spring Boot version from 2.1.5.REALEASE to 2.2.0.RELEASE and by that, my Spring Framework are getting updated.

After the update my application stop working and passing tests. The reason is because I use a library that specify a @AliasFor only on the value field and not on both attributes. Look at the code:

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface EndpointCacheable {
  @AliasFor("prefixKey")
  String value() default "";

  String prefixKey() default "";
}

The @AliasFor documentation says since older versions that is needed to specify the annotation on both attributes that are alias of each other, but no error was thrown in older versions.

The stack trace:

Caused by: org.springframework.core.annotation.AnnotationConfigurationException: Attribute 'prefixKey' in annotation [br.com.stilingue.utilities.cache.annotation.EndpointCacheable] must be declared as an @AliasFor 'value'.
	at org.springframework.core.annotation.AnnotationTypeMapping.resolveAliasTarget(AnnotationTypeMapping.java:183) ~[spring-core-5.2.0.RELEASE.jar:5.2.0.RELEASE]
	at org.springframework.core.annotation.AnnotationTypeMapping.resolveAliasTarget(AnnotationTypeMapping.java:134) ~[spring-core-5.2.0.RELEASE.jar:5.2.0.RELEASE]
	at org.springframework.core.annotation.AnnotationTypeMapping.resolveAliasedForTargets(AnnotationTypeMapping.java:126) ~[spring-core-5.2.0.RELEASE.jar:5.2.0.RELEASE]
	at org.springframework.core.annotation.AnnotationTypeMapping.<init>(AnnotationTypeMapping.java:103) ~[spring-core-5.2.0.RELEASE.jar:5.2.0.RELEASE]
	at org.springframework.core.annotation.AnnotationTypeMappings.addIfPossible(AnnotationTypeMappings.java:109) ~[spring-core-5.2.0.RELEASE.jar:5.2.0.RELEASE]
	at org.springframework.core.annotation.AnnotationTypeMappings.addAllMappings(AnnotationTypeMappings.java:68) ~[spring-core-5.2.0.RELEASE.jar:5.2.0.RELEASE]
	at org.springframework.core.annotation.AnnotationTypeMappings.<init>(AnnotationTypeMappings.java:61) ~[spring-core-5.2.0.RELEASE.jar:5.2.0.RELEASE]
	at org.springframework.core.annotation.AnnotationTypeMappings.<init>(AnnotationTypeMappings.java:46) ~[spring-core-5.2.0.RELEASE.jar:5.2.0.RELEASE]
	at org.springframework.core.annotation.AnnotationTypeMappings$Cache.createMappings(AnnotationTypeMappings.java:217) ~[spring-core-5.2.0.RELEASE.jar:5.2.0.RELEASE]
	at java.util.concurrent.ConcurrentMap.computeIfAbsent(ConcurrentMap.java:330) ~[?:?]
	at org.springframework.core.annotation.AnnotationTypeMappings$Cache.get(AnnotationTypeMappings.java:213) ~[spring-core-5.2.0.RELEASE.jar:5.2.0.RELEASE]
	at org.springframework.core.annotation.AnnotationTypeMappings.forAnnotationType(AnnotationTypeMappings.java:181) ~[spring-core-5.2.0.RELEASE.jar:5.2.0.RELEASE]
	at org.springframework.core.annotation.AnnotationTypeMappings.forAnnotationType(AnnotationTypeMappings.java:168) ~[spring-core-5.2.0.RELEASE.jar:5.2.0.RELEASE]
	at org.springframework.core.annotation.TypeMappedAnnotation.of(TypeMappedAnnotation.java:632) ~[spring-core-5.2.0.RELEASE.jar:5.2.0.RELEASE]
	at org.springframework.core.annotation.MergedAnnotation.of(MergedAnnotation.java:593) ~[spring-core-5.2.0.RELEASE.jar:5.2.0.RELEASE]
	at org.springframework.core.type.classreading.MergedAnnotationReadingVisitor.visitEnd(MergedAnnotationReadingVisitor.java:96) ~[spring-core-5.2.0.RELEASE.jar:5.2.0.RELEASE]
	at org.springframework.asm.ClassReader.readElementValues(ClassReader.java:2775) ~[spring-core-5.2.0.RELEASE.jar:5.2.0.RELEASE]
	at org.springframework.asm.ClassReader.readMethod(ClassReader.java:1183) ~[spring-core-5.2.0.RELEASE.jar:5.2.0.RELEASE]
	at org.springframework.asm.ClassReader.accept(ClassReader.java:688) ~[spring-core-5.2.0.RELEASE.jar:5.2.0.RELEASE]
	at org.springframework.asm.ClassReader.accept(ClassReader.java:400) ~[spring-core-5.2.0.RELEASE.jar:5.2.0.RELEASE]
	at org.springframework.core.type.classreading.SimpleMetadataReader.<init>(SimpleMetadataReader.java:50) ~[spring-core-5.2.0.RELEASE.jar:5.2.0.RELEASE]
	at org.springframework.core.type.classreading.SimpleMetadataReaderFactory.getMetadataReader(SimpleMetadataReaderFactory.java:103) ~[spring-core-5.2.0.RELEASE.jar:5.2.0.RELEASE]
	at org.springframework.core.type.classreading.CachingMetadataReaderFactory.getMetadataReader(CachingMetadataReaderFactory.java:123) ~[spring-core-5.2.0.RELEASE.jar:5.2.0.RELEASE]
	at org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider.scanCandidateComponents(ClassPathScanningCandidateComponentProvider.java:430) ~[spring-context-5.2.0.RELEASE.jar:5.2.0.RELEASE]
	at org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider.findCandidateComponents(ClassPathScanningCandidateComponentProvider.java:316) ~[spring-context-5.2.0.RELEASE.jar:5.2.0.RELEASE]
	at org.springframework.context.annotation.ClassPathBeanDefinitionScanner.doScan(ClassPathBeanDefinitionScanner.java:276) ~[spring-context-5.2.0.RELEASE.jar:5.2.0.RELEASE]
	at org.springframework.context.annotation.ComponentScanAnnotationParser.parse(ComponentScanAnnotationParser.java:132) ~[spring-context-5.2.0.RELEASE.jar:5.2.0.RELEASE]
	at org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:290) ~[spring-context-5.2.0.RELEASE.jar:5.2.0.RELEASE]
	at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:245) ~[spring-context-5.2.0.RELEASE.jar:5.2.0.RELEASE]
	at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:202) ~[spring-context-5.2.0.RELEASE.jar:5.2.0.RELEASE]
	at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:170) ~[spring-context-5.2.0.RELEASE.jar:5.2.0.RELEASE]
	at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:325) ~[spring-context-5.2.0.RELEASE.jar:5.2.0.RELEASE]
	at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:242) ~[spring-context-5.2.0.RELEASE.jar:5.2.0.RELEASE]
	at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:275) ~[spring-context-5.2.0.RELEASE.jar:5.2.0.RELEASE]
	at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:95) ~[spring-context-5.2.0.RELEASE.jar:5.2.0.RELEASE]
	at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:706) ~[spring-context-5.2.0.RELEASE.jar:5.2.0.RELEASE]
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:532) ~[spring-context-5.2.0.RELEASE.jar:5.2.0.RELEASE]
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747) ~[spring-boot-2.2.0.RELEASE.jar:2.2.0.RELEASE]
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) ~[spring-boot-2.2.0.RELEASE.jar:2.2.0.RELEASE]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) ~[spring-boot-2.2.0.RELEASE.jar:2.2.0.RELEASE]
	at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:125) ~[spring-boot-test-2.2.0.RELEASE.jar:2.2.0.RELEASE]
	at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:99) ~[spring-test-5.2.0.RELEASE.jar:5.2.0.RELEASE]
	at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124) ~[spring-test-5.2.0.RELEASE.jar:5.2.0.RELEASE]
	... 47 more

There is an issue or is expected?

Maybe this will break other libs with alias only in one attribute (I know this a library bug, but no error was thrown before).

Thank you.

Activity

self-assigned this
on Oct 30, 2019
added
in: coreIssues in core modules (aop, beans, core, context, expression)
and removed on Oct 30, 2019
added this to the 5.2.1 milestone on Oct 30, 2019
changed the title [-]Issue with AliasFor annotation upgrading from Spring Framework 5.1.7.REALEASE to 5.2.0.RELEASE[/-] [+]Issue with AliasFor annotation upgrading from 5.1.7 to 5.2.0[/+] on Oct 30, 2019
sbrannen

sbrannen commented on Oct 30, 2019

@sbrannen
Member

Maybe this will break other libs with alias only in one attribute (I know this a library bug, but no error was thrown before).

No exception was thrown prior to Spring Framework 5.2 because @AliasFor was not honored with our ASM-based annotation processing.

Thus, the @AliasFor declaration in @EndpointCacheable was effectively ignored until you upgraded to 5.2.

In light of that, you may wish to inform the author of that library that the code in question perhaps does not work as intended with versions of Spring Framework prior to 5.2.

added and removed on Oct 31, 2019
changed the title [-]Issue with AliasFor annotation upgrading from 5.1.7 to 5.2.0[/-] [+]Suppor unidirectional @AliasFor attribute mapping within an annotation[/+] on Oct 31, 2019
sbrannen

sbrannen commented on Oct 31, 2019

@sbrannen
Member

As stated above, there was actually a configuration error in the library code in use.

The fact that Spring Framework 5.2 introduced support for @AliasFor with components introspected using ASM caused the configuration error to be reported (in the form of an exception).

Commit 42e7ade introduced explicit support for unidirectional @AliasFor attribute mappings within an annotation. That makes the configuration error no longer an error and also allows for more lenient @AliasFor usage (within an annotation), both for ASM-based and reflection-based annotation metadata introspection.

I have therefore changed the title of this description accordingly and switched from regression to enhancement.

changed the title [-]Suppor unidirectional @AliasFor attribute mapping within an annotation[/-] [+]Support unidirectional @AliasFor attribute mapping within an annotation[/+] on Oct 31, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

in: coreIssues in core modules (aop, beans, core, context, expression)type: enhancementA general enhancement

Type

No type

Projects

No projects

Relationships

None yet

    Development

    No branches or pull requests

      Participants

      @sbrannen@jhoeller@lucasoares@spring-projects-issues

      Issue actions

        Support unidirectional @AliasFor attribute mapping within an annotation · Issue #23834 · spring-projects/spring-framework