Skip to content

Duplicate @Bean name inspection is silent when overriding is allowed but Spring silently drops one method #698

Closed

Description

@imuromtsev

Summary

With spring.main.allow-bean-definition-overriding=true, the duplicate @Bean name inspection reports nothing for two @Bean methods that declare the same bean name. Spring does not fail there, but it does not use both methods either: it registers one of them and silently never calls the other. The ignored method is dead code that looks like a working bean factory, and which one is ignored changes between Spring Framework versions.

Where (public/main 7d9574f)

modules/spring-core/src/main/kotlin/com/explyt/spring/core/inspections/SpringDuplicateBeanNameInspection.kt:36: checkClass returns null when overridingOf (:55-64) answers Overriding.ALLOWED for a known true value of spring.main.allow-bean-definition-overriding (ALLOW_OVERRIDING_KEY, :90). The same applies on the open stack #692 (#686) → #695 (#689), where the verdict is decided per collision but overriding allowed still yields no problem outside the Spring 7 rule.

What Spring does (probes on real spring-context jars, AnnotationConfigApplicationContext, overriding allowed)

Pair 5.3.31 / 6.0.11 / 6.1.13 6.2.0 6.2.1+ 7.0.9
one class: @Bean A a() + @Bean("a") A b() starts, bean a from b(), a() never called starts, bean a from a(), b() never called starts, bean a from b() fails for a full @Configuration (#686)
hierarchy: base @Bean a() + subclass @Bean("a") b() subclass method kept base method kept subclass method kept fails for a full @Configuration
lite class (@Component with @Bean methods) b() kept a() kept b() kept starts
name is the primary name of one method and an alias of the other, @Bean({"a","svc"}) x() + @Bean("svc") y() 5.3.31: only x() runs (both declaration orders); 6.0.11, 6.1.13: both run, svc points to y() both run (not probed) x() declared first: both run; y() declared first: only x() runs

So for a pair of primary names the app starts and exactly one method is dropped, and the dropped method is not predictable from the source (6.2.0 drops the other one than 6.1 and 6.2.1). For a primary name that is also another method's alias, Spring 5.3 and 7.0 can drop one method depending on the declaration order, while 6.0–6.2 keep both and only move the alias.

Proposal

When overriding is allowed and the collision is between primary names (the first declared @Bean name, else the method name, of both methods), report a weak warning on the second method: "Bean ''a'' is also declared by ''…''; Spring registers only one of the two methods and never calls the other". Do not name the kept method. For a primary name that is another method's alias, use a hedged wording ("may never call") on versions where the probe shows a dropped method (before 6.0, and 7.x), and probe 6.2.1+ first. Skip it where #686 already reports an error (Spring 7, full @Configuration with enforceUniqueMethods, primary names).

Related

#597, #686, #689 (PR #695), #668.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions