David Resnick
David Resnick

Reputation: 4981

How can I use Spring XML configuration to set a bean property with list of all beans of a certain type?

I have the following XML configuration:

<bean id="bean1" class="Simple"/>
<bean id="bean2" class="Simple"/>

<bean id="tasks" class="java.util.ArrayList">
    <constructor-arg>
        <list>
            <ref bean="bean1" />
            <ref bean="bean2" />                
        </list>
    </constructor-arg>
</bean>

<bean id="list" class="Comp">
    <property name="tasks" ref="tasks"/>
</bean>

The "tasks" contains all beans of type Simple. The problem with this is that I might forget to add a Simple bean I've configured to the list.

I could do this programatically using

Map map = context.getBeansOfType(Simple.class);

and setting the list bean with the beans retrieved.

Is there any way of doing this using just XML configuration?

Upvotes: 11

Views: 30796

Answers (2)

rudolfson
rudolfson

Reputation: 4146

I would suggest writing your own FactoryBean for creating such a list. This would be reusable and then configurable using XML only. The FactoryBean would look like

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.util.Assert;

public class CollectingListFactoryBean implements FactoryBean, ApplicationContextAware {
    private ApplicationContext appCtx;
    private Class type;

    public Object getObject() {
        Assert.notNull(type, "type must be initialized");
        List result = new ArrayList();
        result.addAll(appCtx.getBeansOfType(type).values());
        return result;
    }

    public Class getObjectType() {
        return List.class;
    }

    public boolean isSingleton() {
        return false;
    }

    public void setApplicationContext(ApplicationContext applicationContext) {
        this.appCtx = applicationContext;
    }

    public void setType(Class type) {
        this.type = type;
    }
}

Then your XML configuration would be

<bean id="bean1" class="Simple"/>
<bean id="bean2" class="Simple"/>

<bean id="tasks" class="CollectingListFactoryBean">
    <property name="type" value="Simple" />
</bean>

<bean id="list" class="Comp">
    <property name="tasks" ref="tasks"/>
</bean>

NOTE: I didn't have the time to test the example above. I just used code I already had as a template. ;) Especially I'm not sure if passing Simple as a Class argument for the type property works this way. Just give it a try. In the worst case you would have to use String as the property type and use Class.forName(type) to get your class. But my guess is that Spring does this transformation for you.

EDIT Even though this solution should work, I recommend Robert Munteanu's answer.

Upvotes: 4

Robert Munteanu
Robert Munteanu

Reputation: 68268

Your context file should like this:

<bean id="bean1" class="Simple"/>
<bean id="bean2" class="Simple"/>

<bean id="list" class="Comp" autowire="byType"/>

Note the autowire="byType" addition, and the autowiring documentation.

Upvotes: 9

Related Questions