Samuel Rossille
Samuel Rossille

Reputation: 19838

How to contribute to a list property of a bean using Spring?

I have 3 projects:

Each of the products depends on the framework, but they don't know each other.

I have 3 spring configuration files: one for each project. The configuration file of each product includes (with <import resource="classpath:/...) the configuration file of the framework.

In the framework there is a bean called "manager", which has a property List<AnInterface> theList. The "manager" has a addXxx(anImplementation), which adds elements to the list).

The framework, and each of the product provide implementations of AnInterface, which have to be added to theList.

So in the end, when product-a is running, the manager contains implementations from the framework, and from product-a, idem for product-b

What is the best practice to perform this initialization with Spring ?

The only solution I could think about is to create a dedicated class which contructor will take the manager and a list of contributions, and add them to the manager, but it's ugly because 1/ It manipulate external objects in the constructor, 2/ I have to create a dummy class just to initialize other classes... I don't like that.

Upvotes: 1

Views: 3547

Answers (2)

Samuel Rossille
Samuel Rossille

Reputation: 19838

I have accepted the answer of Grzegorz because it's a clean solution to my initial problem, but here as an alternate answer, the a technical solution to contribute to a list property of an existing bean.

<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    <property name="targetObject" ref="manager"/>
<property name="targetMethod"><value>addXxx</value></property>
<property name="arguments"><list value-type="com.xxx.AnInterface">
    <value ref="impl1" />
    <value ref="impl2" />
    ...
    </list></property>
</bean>

Upvotes: 1

Grzegorz Żur
Grzegorz Żur

Reputation: 49171

I think that code should not know about Spring if it is not really needed. Therefore I would do all initialization in Spring config.

We can use bean definition inheritance and property overriding to do it.

Framework class

public class Manager {

    private List<AnInterface> theList;

    public void init() {
         // here we use list initialized by product
    }    

}

Framework context

<bean id="manager"
      init-method="init"
      abstract="true"
      class="Manager">
    <property name="theList">
        <list/> <!-- this will be overriden or extnded -->    
    </property>
</bean>

Product A context

<bean id="managerA"
      parent="manager"
      scope="singleton"
      lazy-init="false">
    <property name="theList">
        <list>
            <ref bean="impl1"/>
            <ref bean="impl2"/>
        </list>    
    </property>
</bean>

Watch out for parent and child properties in such configuration. Not all are inherited from parent. Spring documentation specifies:

The remaining settings are always taken from the child definition: depends on, autowire mode, dependency check, singleton, scope, lazy init.

Moreover, there is also collection merging in Spring so by specifing in child bean

<list merge="true">

you can merge parent and child lists.


I have observed this pattern in a number of projects and some extendable Web frameworks based on Spring.

Upvotes: 2

Related Questions