Reputation: 24134
We have an application where we are trying to inject an empty java.util.HashSet
into a member of type java.util.Set
, in a class which itself is a @Component
. Spring seems to inject a HashSet
with one element of the containing type. Any idea why Spring doesn't just inject an empty set?
Set element class:
@Component
public class SetElement
{
private String value;
public String getValue()
{
return value;
}
}
Class that contains a Set as a member:
@Component
public class MyClassWithSet
{
@Autowired
private Set<SetElement> setOfElements;
protected void setStringSet(Set<SetElement> stringSet)
{
this.setOfElements = stringSet;
}
public Set<SetElement> getStringSet()
{
return Collections.unmodifiableSet(setOfElements);
}
}
Spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
">
<bean id="setOfElements" class="java.util.HashSet" />
<context:component-scan base-package="com.vikdor.db " />
</beans>
Sample test case to confirm the behavior
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations =
{ "classpath:META-INF/spring.xml" })
public class SpringSetTest
{
@Autowired
private MyClassWithSet myClassWithSet;
@Test
public void test()
{
assertNotNull(myClassWithSet);
assertNotNull(myClassWithSet.getStringSet());
assertTrue(myClassWithSet.getStringSet().isEmpty());
}
}
Upvotes: 2
Views: 1238
Reputation: 8932
If you use @Autowired
on a typed collection instance, then all beans in the application context that satisfy the type are injected:
It is also possible to provide all beans of a particular type from the ApplicationContext by adding the annotation to a field or method that expects an array of that type [...] The same applies for typed collections:
public class MovieRecommender {
private Set<MovieCatalog> movieCatalogs;
@Autowired
public void setMovieCatalogs(Set<MovieCatalog> movieCatalogs) {
this.movieCatalogs = movieCatalogs;
}
// ...
}
Thus, your single instance of SetElement
is injected into the @Autowired Set<SetElement>
. A possible solution would be to use a setter for the field. Alternatively, you could use the @Qualifier
annotation or the @Resource
annotation to refer to the bean by name.
Upvotes: 4