Saturday, October 6, 2012

Using Collection Merging in Spring to re-use a list

Recently, I came across a requirement where I had a set of rules to be run on various sub-types of a business object--Invoice. All sub-types shared a common set of rules and then each sub-type has some exclusive set of rules to be run along with those in the common set. I was using Spring for dependency injection and did it as follows, initially:

<bean id="rule1" class="com.vikdor.rules.Rule1" />
<bean id="rule2" class="com.vikdor.rules.Rule2" />
<bean id="rule3" class="com.vikdor.rules.Rule3" />
<bean id="rule4" class="com.vikdor.rules.Rule4" />
<bean id="rule5" class="com.vikdor.rules.Rule5" />

<util:list id="normalInvRules">
    <ref bean="rule1" />
    <ref bean="rule3" />
    <ref bean="rule5" />
    <ref bean="rule4" />
</util:list>

<util:list id="prepaidInvRules">
    <ref bean="rule1" />
    <ref bean="rule3" />
    <ref bean="rule5" />
    <ref bean="rule2" />
</util:list>
This obviously was not going to scale in my use case where I have good number of rules to be run and the number of sub-types are also more. I was wondering if there is a way to define the common list and then re-use it while defining the actual list of rules for a given type of invoice and then I came across Collection Merging concept in Spring where we can define a parent element and then have child elements inherit the properties from the parent element and override them (i.e. when there is a conflict, the child property definition takes precedence) and modified my configuration as follows and it works great!
<bean id="rule1" class="com.krovi.rules.Rule1" />
    <bean id="rule2" class="com.krovi.rules.Rule2" />
    <bean id="rule3" class="com.krovi.rules.Rule3" />
    <bean id="rule4" class="com.krovi.rules.Rule4" />
    <bean id="rule5" class="com.krovi.rules.Rule5" />

    <bean id="commonList"
        class="org.springframework.beans.factory.config.ListFactoryBean">
        <property name="sourceList">
            <list>
                <ref bean="rule1" />
                <ref bean="rule2" />
                <ref bean="rule3" />
            </list>
        </property>
    </bean>
    <bean id="firstExecutorRules" parent="commonList"
        class="org.springframework.beans.factory.config.ListFactoryBean">
        <property name="sourceList">
            <list merge="true">
                <ref bean="rule4" />
            </list>
        </property>
    </bean>
    <bean id="secondExecutorRules" parent="commonList"
        class="org.springframework.beans.factory.config.ListFactoryBean">
        <property name="sourceList">
            <list merge="true">
                <ref bean="rule5" />
            </list>
        </property>
    </bean>

No comments :

Post a Comment