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

QualifierAnnotationAutowireCandidateResolver.checkQualifier does identity checks when comparing arrays used as qualifier fields #32106

Closed
nicholashagen opened this issue Jan 24, 2024 · 0 comments
Assignees
Labels
in: core Issues in core modules (aop, beans, core, context, expression) status: backported An issue that has been backported to maintenance branches type: bug A general bug
Milestone

Comments

@nicholashagen
Copy link

Affects: \spring-beans 6.1.+ (likely newer versions as well)


Overview

We have a custom annotation that we used to attach as qualifier to bean definitions through a post processor. When we added a new String[] array to that annotation, beans no longer matched. This is due to QualifierAnnotationAutowireCandidateResolver.checkQualifier eventually doing if (!expectedValue.equals(actualValue)) { which fails for arrays. The equals methods on arrays purely does identity rather than deep equality of the items.

Deep-Dive

We define a custom annotation as:

@Inherited
@Target({ ElementType.FIELD, ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Qualifier
@Autowired
public @interface MyAnnotation {

	String value();

	String[] inherits() default { };

}

We create custom bean definitions via:

MyAnnotation annotation = getAnnnotation(); // this is handled elsewhere
RootBeanDefinition rbd = (RootBeanDefinition) BeanDefinitionBuilder.rootBeanDefinition(MyFactoryBean.class)
     getBeanDefinition();
AutowireCandidateQualifier qualifier = new AutowireCandidateQualifier(MyAnnotation.class, annotation.value());
qualifier.setAttribute("inherits", annotation.inherits());
rbd.addQualifier(qualifier);
registry.registerBeanDefinition(beanName, rbd);

We then try to inject this bean via:

@Component
public class MyClass {

      public MyClass(@MyAnnotation(value = "foo", inherits = "bar") MyClass myClass) {
           ....
      }
}

This works fine with inherits is not on the annotation, but fails when the array is added.

Eventually this calls QualifierAnnotationAutowireCandidateResolver.checkQualifier. This fetches the qualifier from the bean definition per the post-processor. It then fetches AnnotationUtils.getAnnotationAttributes(annotation); to get all the properties of the target in MyClass (ie: @MyAnnotation(value = "foo", inherits = "bar")). It traverses each property and compares against the qualifier attributes. That eventually results in getting the string array from the qualifier attributes and the annotation property. Those will always end up being different identities since annotations return a new value each time. Even if not, because of how we set the attributes, they would be. It then calls if (!expectedValue.equals(actualValue)) { which fails since arrays use identity comparison not deep equality checks of each item.

Would it make sense here to do a comparison checks that is array-aware and then compare the items rather than purely identity?

We ended up finding a better workaround where we use rbd.setQualifiedElement and copy the annotation into that. This bypasses the qualifier checks and just compares the annotation directly which works as expected.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Jan 24, 2024
@jhoeller jhoeller added type: bug A general bug in: core Issues in core modules (aop, beans, core, context, expression) and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Jan 24, 2024
@jhoeller jhoeller self-assigned this Jan 24, 2024
@jhoeller jhoeller added this to the 6.1.4 milestone Jan 24, 2024
@jhoeller jhoeller added the for: backport-to-6.0.x Marks an issue as a candidate for backport to 6.0.x label Jan 24, 2024
@github-actions github-actions bot added status: backported An issue that has been backported to maintenance branches and removed for: backport-to-6.0.x Marks an issue as a candidate for backport to 6.0.x labels Jan 24, 2024
@jhoeller jhoeller added the for: backport-to-5.3.x Marks an issue as a candidate for backport to 5.3.x label Jan 24, 2024
@github-actions github-actions bot removed the for: backport-to-5.3.x Marks an issue as a candidate for backport to 5.3.x label Jan 24, 2024
jhoeller added a commit that referenced this issue Jan 24, 2024
jhoeller added a commit that referenced this issue Jan 24, 2024
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) status: backported An issue that has been backported to maintenance branches type: bug A general bug
Projects
None yet
Development

No branches or pull requests

3 participants