Question

Is there a way in Spring that I can auto populate a list with all of beans of a type AND any of its subtypes? I have a setter method that looks like:

setMyProp(List<MyType> list)

And I would like to autowire in any beans of MyType and all subclasses of MyType.

Thanks, Jeff

Was it helpful?

Solution

Yup, you can do this. The spring docs say:

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.

Note that it says you need to expect an array, not a list. This makes sense, because generic type erasure means a list may not work at runtime. However, take the following unit test, which works:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">  

    <bean class="test.Test.TypeB"/>
    <bean class="test.Test.TypeC"/>
    <bean class="test.Test.TypeD"/>
</beans>

and this unit test:

package test;

@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
public class Test {

    private @Autowired List<TypeA> beans;

    @org.junit.Test
    public void test() {
        assertNotNull(beans);
        assertEquals(2, beans.size());
        for (TypeA bean : beans) {
            assertTrue(bean instanceof TypeA);
        }
    }       

    public static interface TypeA {}
    public static class TypeB implements TypeA {}
    public static class TypeC extends TypeB {}
    public static class TypeD {}

}

So officially, you're supposed to autowire TypeA[], not List<TypeA>, but the List works good.

OTHER TIPS

If it's acceptable to fill the list from your application code and not from within the bean definition file you could use the org.springframework.beans.factory.xml.XmlBeanFactory and ask it "getBeansOfType( MyType.class )". This gives you all beans of type (and subtype) of MyType.

If you can use @Autowired inside the code to be populated you can safely use the way mentioned by skaffman. If you insist on XML configuration there is a small library called Hera to achieve this. Esentially configuration of a scenario described by you looks like this:

<bean id="client" class="..">
    <property name="injectDynamicListHere">
        <hera:list class="my.custom.SuperType" />
    </property>
</bean>

This will inject all top-level Spring beans implementing SuperType as List into the client bean.

Short answer: no.

Long answer: Java generics work by type erasure, meaning that at runtime that parameter is simply a List, not a List of a generic type. As such you can't figure out that it is meant to be of parameter type MyType so it wouldn't be possible to implement this behaviour.

That being said, there are alternative ways of doing this. The most obvious seems to be to listen for bean creation and then seeing if they are of MyType (or subclasses) and then keeping a reference.

There is probably a few ways to do this. One is creating a bean post-processor. This way you'll get notified of every bean that's created.

Due to legacy code and missing @Autowired I solve it like:

MyBean implements ApplicationContextAware{

  @Override
  public void setApplicationContext(ApplicationContext ctx) throws BeansException {
    final Map<String, HttpRequestHandlerTemplate> beansOfType = ctx.getBeansOfType(RequiredBean.class);
    ...
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top