Reputation: 24134
I have a bunch of rules to be injected into a set of classes, something like below:
<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="commonRules">
<ref bean="rule1" />
<ref bean="rule3" />
<ref bean="rule5" />
</util:list>
<util:list id="normalInvRules">
<!-- Include common rules -->
<ref bean="rule4" />
</util:list>
<util:list id="prepaidInvRules">
<!-- Include common rules -->
<ref bean="rule2" />
</util:list>
How can I include the common rules list in the lists corresponding to normalInvRules
and prepaidInvRules
?
The number of rules (e.g. rule1, rule2 etc.,) are more and the number groups (normalInvRules, prepaidInvRules etc.,) are also more. So, I am wondering if there is a way to avoid repeating the common rules and just list only the specific ones and include the reference to the common list.
Upvotes: 2
Views: 10946
Reputation: 24134
Thanks for the responses. This is how I have finally addressed it using Collection Merging
:
<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>
Upvotes: 1
Reputation: 49935
I like the approach suggested by @GreyBeardedGeek, just want to throw in a few more suggestions:
a. Doing it using @Configuration
with the base rules list in xml:
@Configuration
@ImportResource("classpath:/baseconfig.xml")
public static class RulesConfiguration{
@Resource List<Rule> commonRules;
@Bean
public List<Rule> normalInvRules(){
List<Rule> rules = new ArrayList<Rule>();
rules.addAll(commonRules);
rules.add(new Rule());
return rules;
}
}
b. Using a custom factory bean, responsible for extending a list:
class ListExpandingFactoryBean<T> implements FactoryBean<List<T>>{
private List<T> baseList;
private List<T> extendedList;
@Override
public List<T> getObject() throws Exception {
List<T> consolidatedList = new ArrayList<T>();
consolidatedList.addAll(baseList);
consolidatedList.addAll(extendedList);
return consolidatedList;
}
@Override
public Class<?> getObjectType() {
return List.class;
}
@Override
public boolean isSingleton() {
return false;
}
public void setBaseList(List<T> baseList) {
this.baseList = baseList;
}
public List<T> getExtendedList() {
return extendedList;
}
public void setExtendedList(List<T> extendedList) {
this.extendedList = extendedList;
}
}
and using it this way:
<bean name="normalInvRules" class="ListExpandingFactoryBean" p:baseList-ref="commonRules">
<property name="extendedList">
<list>
<ref bean="bean4"/>
</list>
</property>
</bean>
Upvotes: 4
Reputation: 92
You may create a class with common rules and auto wire them in other rules? Would n't that work?
You can take the same approach using XML config and inject it using ref attribute as well.
Upvotes: 0
Reputation: 30088
There is a feature called 'collection merging' that does exactly this. See section 3.3.3.4.1. "Collection merging" in the Spring documentation or the 2008 blog post (with an example) that I wrote on the subject.
Upvotes: 5