Simple test class showing my problem:
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringTest.OptionalConfiguration.class)
public class SpringTest {
static class Item extends Object {}
@Configuration
static class OptionalConfiguration {
@Bean
List<Item> someString() {
return new ArrayList<>();
}
@Bean
Object foo(List<Item> obj) {
return new Object();
}
}
@Test
public void testThis() {
}
}
Result:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [SpringTest$Item] found for dependency [collection of SpringTest$Item]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
If I change from List<Item>
to Item
, things work.
Is this by design? Any workarounds? I'd need to provide a List
of items - sometimes empty, sometimes with items, depending on runtime configuration.
I am aware that if I specify bean(s) with type Item, autowiring List<Item>
works. However, I'd like to have a bean with type List<Item>
(or if I can't have that, a List
).
Using Spring 4.2.4.
That snippet will work fine in Spring 4.3+. The documentation states
That said, as of 4.3, collection/map and array types can be matched through Spring’s
@Autowired
type matching algorithm as well [which is also used for@Bean
argument resolution], as long as the element type information is preserved in@Bean
return type signatures or collection inheritance hierarchies. In this case, qualifier values can be used to select among same-typed collections, as outlined in the previous paragraph.
Pre 4.3, when Spring sees
@Bean
Object foo(List<Item> obj) {
it attempts to create a List
object dynamically, containing all the Item
beans found in the ApplicationContext
. Your ApplicationContext
doesn't contain any, so Spring reports an error.
Here are some workarounds. This
@Bean
Object foo() {
List<Item> someString = someString();
return new Object();
}
directly uses the cached bean factory method, someString
.
This
@Resource(name = "someString")
private List<Item> items;
// and access 'items' wherever you need it in the configuration
works because
If you intend to express annotation-driven injection by name, do not primarily use @Autowired, even if is technically capable of referring to a bean name through @Qualifier values. Instead, use the JSR-250 @Resource annotation, which is semantically defined to identify a specific target component by its unique name, with the declared type being irrelevant for the matching process. @Autowired has rather different semantics: After selecting candidate beans by type, the specified String qualifier value will be considered within those type-selected candidates only, e.g. matching an "account" qualifier against beans marked with the same qualifier label.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With