Skip to content

fix: Offer and resolve @Qualifier bean names by the type of a covariant @Bean override (#680) - #696

Merged
imuromtsev merged 4 commits into
mainfrom
imuromtsev/covariant-override-readers
Oct 14, 2026
Merged

imuromtsev merged 4 commits into
mainfrom
imuromtsev/covariant-override-readers

Conversation

@imuromtsev

Copy link
Copy Markdown
Collaborator

Purpose

#594 (#681) types a superclass @Bean method that a @Configuration subclass overrides with a narrower return type by the override, as Spring does. @Qualifier completion and references still read the raw superclass method, so for

class Base { @Bean Animal animal() { … } }
@Configuration class Child extends Base { @Override Dog animal() { … } }
class Consumer { @Autowired @Qualifier("animal") Dog dog; }

completion did not offer animal and the qualifier did not resolve, although the autowiring inspection finds the bean. Gap 1 of #680.

Change

  • SpringBeanService.getBeanCandidates matches factory beans by the effective factory method (the override, when there is one) and maps the matches back to the @Bean declaration, which keeps supplying the name, qualifiers and @Primary; the reference still resolves to the @Bean declaration. A bean that is not overridden is unchanged.
  • The declaration → effective factory map is computed once inside the cached factory map of the bean model (SpringSearchService.getComponentBeanFactories, same tracker, no new lock), and BeanFactoryMethods.overrideIn returns at once for a factory declared in the configuration class itself, so completion and resolve do not walk class hierarchies.
  • Native mode is unchanged (its factories map to themselves).

Not in this PR (remaining #680 gaps)

  • Native-mode readers (NativeSearchService.getBeanPsiMethods, findInArray) — not reachable in light test fixtures.
  • Two configuration subclasses of one base with different overrides; a base class that is itself a @Configuration — need a probe first.

Verification

  • Red commit c0e5890 (Java and Kotlin twins): completion offers animal and the qualifier resolves for a Dog injection point — both failed; controls (Animal injection point, a base that already returns Dog) passed.
  • Red commit 243d10a (review follow-up): the effective factory map is the same cached instance while PSI is unchanged, and overrideIn does not search the hierarchy of the declaring configuration (a throwing decoy class) — both failed in both twins.
  • After the fixes (839e0bd, 605a6ff): BeanFactoryMethodsTest 27 + 26, CovariantOverrideQualifierReferenceTest 6 + 6, ScopedBeanInjectionResolverTest, SpringBeanIncorrectAutowiringInspectionTest and all SpringBeanLineMarkerProvider* twins: 465 tests, 0 failures.
  • All modules (:spring-bootstrap:test --rerun-tasks on 605a6ff, fresh JUnit XML): spring-core 2407, spring-web 905 (6 skipped), spring-ai 776, spring-data 140, jpa 138, base 35, aop 6, security 6, initializr 5; 0 failures, 0 errors.

Main only: BeanFactoryMethods.overrideIn came with #681.

Refs #680

@imuromtsev imuromtsev added the in:spring-core Spring Core or Spring Boot Core issues label Oct 13, 2026
@github-actions

Copy link
Copy Markdown
TestsPassed ✅Skipped ⚠️Failed
JUnit Test Report4418 ran4412 passed6 skipped0 failed

@imuromtsev
imuromtsev merged commit 72ea7ef into main Oct 14, 2026
2 checks passed
@imuromtsev
imuromtsev deleted the imuromtsev/covariant-override-readers branch October 14, 2026 07:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

in:spring-core Spring Core or Spring Boot Core issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant