Skip to content

Support unidirectional @AliasFor attribute mapping within an annotation #23834

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

Closed
lucasoares opened this issue Oct 18, 2019 · 2 comments
Closed
Assignees
Labels
in: core Issues in core modules (aop, beans, core, context, expression) type: enhancement A general enhancement
Milestone

Comments

@lucasoares
Copy link

lucasoares commented Oct 18, 2019

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.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Oct 18, 2019
@jhoeller jhoeller self-assigned this Oct 30, 2019
@jhoeller jhoeller added in: core Issues in core modules (aop, beans, core, context, expression) type: regression A bug that is also a regression and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Oct 30, 2019
@jhoeller jhoeller added this to the 5.2.1 milestone Oct 30, 2019
@jhoeller jhoeller 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 Oct 30, 2019
@sbrannen
Copy link
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.

@sbrannen sbrannen added type: enhancement A general enhancement and removed type: regression A bug that is also a regression labels Oct 31, 2019
@sbrannen sbrannen changed the title Issue with AliasFor annotation upgrading from 5.1.7 to 5.2.0 Suppor unidirectional @AliasFor attribute mapping within an annotation Oct 31, 2019
@sbrannen
Copy link
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.

@sbrannen sbrannen changed the title Suppor unidirectional @AliasFor attribute mapping within an annotation Support unidirectional @AliasFor attribute mapping within an annotation Oct 31, 2019
pull bot pushed a commit to scope-demo/spring-framework that referenced this issue Oct 31, 2019
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

4 participants