-
Notifications
You must be signed in to change notification settings - Fork 38.3k
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
Direct autowiring of existing collection subtype bean if ApplicationContext
contains beans of type T
#30022
Comments
java.util.Queue<T>
if ApplicationContext
contains beans of type T
This is a known limitation and effectively a duplicate of #16794. See the discussions in that issue for details. Known workarounds:
Aside from those workarounds, there is also the option to remove the The reason is that Spring will first look for beans of type Thus, when you remove the In summary, if you do not need to have the |
To help you experiment with the options, I've reduced your examples to the following single test class. The test passes as-is, but if you reinstate the @SpringJUnitConfig
class AutowiredQueueTests {
@Autowired
// @Autowired @Qualifier("queue")
// @Resource
Queue<String> queue;
@Test
void test() {
assertThat(this.queue).containsExactly("foo", "bar");
}
@Configuration
static class Config {
// @Bean
String foo() {
return "foo";
}
// @Bean
String bar() {
return "bar";
}
@Bean
Queue<String> queue() {
Queue<String> queue = new ArrayDeque<>();
queue.add(foo());
queue.add(bar());
return queue;
}
}
} |
As a proof of concept, I inserted the following lines of code... // If a single bean of the exact collection type exists, do not resolve beans of the elementType into a
// new collection. Rather, fall back to autowiring the single bean of the exact collection type as-is.
if (determineAutowireCandidate(findAutowireCandidates(beanName, type, descriptor), descriptor) != null) {
return null;
} ... into Line 1476 in 6825a84
That appears to achieve the desired effect and does not cause any other tests in Spring Framework's test suite to fail -- though it is a change in behavior and can cause existing applications to fail or behave differently. @jhoeller, putting aside the comments you made in #16794 against changing this behavior, what are your thoughts on supporting such use cases in a future version of Spring Framework? |
As a side note for @yvasyliev and anyone else reading this issue... If you want Spring to collect beans of a certain type into a collection type that is not supported by Spring out of the box, you can always register your own custom For example, if we want Spring to find all beans of type @SpringJUnitConfig
class AutowiredQueueTests {
@Autowired
Queue<String> queue;
@Test
void test() {
assertThat(this.queue).containsExactly("foo", "bar");
}
@Configuration
static class Config {
@Bean
String foo() {
return "foo";
}
@Bean
String bar() {
return "bar";
}
@Bean
ConversionService conversionService() {
ConversionServiceFactoryBean factory = new ConversionServiceFactoryBean();
factory.setConverters(Set.of(new CollectionToQueueConverter()));
factory.afterPropertiesSet();
return factory.getObject();
}
}
@SuppressWarnings("rawtypes")
static class CollectionToQueueConverter implements Converter<Collection<?>, Queue<?>> {
@Override
public Queue<?> convert(Collection<?> source) {
return new ArrayDeque<>(source);
}
}
} Note, however, that the above |
In light of this issue, #29987, as well as the popularity of issues such as #16794 (and all of the related issues linked from that issue), we have decided to revisit this topic for Spring Framework 6.1. Specifically, our goal is to support direct injection of a collection bean even if the bean factory contains beans of the type contained in the collection bean. Things to consider:
|
java.util.Queue<T>
if ApplicationContext
contains beans of type T
Collection<T>
bean if ApplicationContext
contains beans of type T
It's worth noting that you may also mark the individual |
I'm inclined to repurpose this ticket for narrowing our collection of beans algorithm in 6.1, along the lines of #19684: just supporting For the time being and for enforcing direct matching even for a |
Collection<T>
bean if ApplicationContext
contains beans of type T
ApplicationContext
contains beans of type T
This is implemented as a three-step check now: first searching for multiple beans in case of well-known collection types (which is performance-relevant since this is the most common use of collections at injection points), then for direct matches with collection beans (for standard as well as custom collection types), and only then as a fallback also custom collection declarations for multiple beans. So we effectively attempt to resolve e.g. a In practice, please do not mix individual beans and collection beans of the same type unless you use qualifiers for them. If there are just individual beans or just a collection bean for a certain dependency type, the resolution is always straightforward. |
The current focus of this issue is described in #30022 (comment).
For background information, the original issue title and description follow.
Previous title: "Cannot autowire
java.util.Queue<T>
ifApplicationContext
contains beans of typeT
"Affects: spring-context 5.3.25
I'm not able to autowire
java.util.Queue
in console app usingspring-context
.There is a quick code example:
When I run this code, I receive the next error in console:
Note 1: If I replace
@Autowired
with@javax.annotation.Resource
, the code will work.Note 2: If I replace
java.util.Queue
withjava.util.Set
, the code will work.Since the issue is reproduced for
java.util.Queue
only, it seems like a bug.The text was updated successfully, but these errors were encountered: