23

I have defined a with some "common" values. How can I extend the common list by additional values to various new beans?

<util:list id="myCommonList" list-class="java.util.LinkedList">
 <bean .../>
 <bean .../>
 <bean .../>
 <bean .../>
</util:list>


<bean id="extension" parent="myCommonList">
  <bean ref="additionalValue"/>
</bean>

Will this overwrite the list or extend it?

Bastl
  • 1,431
  • 3
  • 14
  • 15
  • After reading many solutions, I came up with the following one: http://stackoverflow.com/questions/14520536/spring-collection-merge/14521537#14521537 – BTakacs Jan 25 '13 at 15:03
  • See also http://stackoverflow.com/questions/4656460/how-to-extend-already-defined-lists-and-maps-in-spring-application-context – Vadzim May 20 '13 at 16:19

6 Answers6

36

You can do it, but not using <util:list>, which is just a convenience syntax. The container does provide a "collection merging" function, but you have to use the "old" style:

<bean id="parent" class="org.springframework.beans.factory.config.ListFactoryBean">
    <property name="sourceList">
        <list>
            <value>X</value>
        </list>
    </property>
</bean>

<bean id="child" parent="parent" class="org.springframework.beans.factory.config.ListFactoryBean">
    <property name="sourceList">
        <list merge="true">
            <value>Y</value>
        </list>
    </property>
</bean>
skaffman
  • 398,947
  • 96
  • 818
  • 769
11

Based on skaffman's answer, you can achive this way:

<util:list id="parent">
    <value>X</value>
</util:list>

<bean id="child" parent="parent" class="org.springframework.beans.factory.config.ListFactoryBean">
    <property name="sourceList">
        <list merge="true">
            <value>Y</value>
        </list>
    </property>
</bean>
Bird Bird
  • 430
  • 4
  • 8
  • I Just tried it and it doesn't work. Only overriding the util:list with the old + new value(s) works, unfortunately. In my case I inherit the util:list from a parent project, but this should do not change anything I guess. – BAERUS Nov 06 '15 at 11:49
4

To append list2's elements to list1 use the following spring config.

<util:list id="list1">
    <value>1</value>
<util:list>

<util:list id="list2">
    <value>3</value>
    <value>5</value>
<util:list>

<bean
    class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    <property name="targetObject" ref="list1" />
    <property name="targetMethod" value="addAll" />
    <property name="arguments" ref="list2" />
</bean>
adrock20
  • 175
  • 1
  • 7
2

According to this JIRA; there is no trivial solution for this (currently, but hopefully in 3.1 there will be), though there are several workarounds; e.g. this one.

abalogh
  • 8,239
  • 2
  • 34
  • 49
1

Today I was having this issue too. For me the acceptable solution was to use SpEL and while SpEL doesn't supports multiple statements - create two auxiliary classes that appends lists.

Context might be implemented like this:

<util:list id="list1">
    <value>str1</value>
    <value>str2</value>
</util:list>

<util:list id="list2">
    <value>str3</value>
    <value>str4</value>
</util:list>

<bean ...>
    <property name="propertyThatRequiresMergedList"
        value="#{ new x.y.springs.StringListsMerger().merge(@list1, @list2) }" />
</bean>

And classes:

package x.y.springs;

import java.util.List;

public abstract class ListsMerger<T extends List> {
    public T merge(T ... lists) {
        T container = createContainer();
        for (T list : lists) {
            container.addAll(list);
        }
        return container;
    }
    public abstract T createContainer();
}


package x.y.springs;

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

public class StringListsMerger extends ListsMerger<List<String>> {

    @Override
    public List<String> createContainer() {
        return new ArrayList<String>();
    }

}
Mikhail Tsaplin
  • 642
  • 1
  • 9
  • 21
  • This is quite cool although not really sure why you didnt just use a concrete implementation of the generic ListsMerger class. – DD. May 14 '13 at 11:18
  • DD. Are you asking about using of something like `#{ new x.y.springs.ListsMerger().merge(@list1, @list2) }"`? This will not work if there is no any usage of ListMerger in java files, otherwise it will not compile ListMerger implementation for String. – Mikhail Tsaplin May 16 '13 at 15:25
  • "#{ new x.y.springs.GenericListsMerger().merge(@list1, @list2) }" – DD. May 16 '13 at 21:02
  • Just have a generic class...why do you need to create a concrete class for every type? – DD. May 16 '13 at 21:02
0

You can overwrite or add any other bean in this list by following the below snippet.

For example: this is your bean which needs to be injected in the AAA util:list mentioned below.

<bean id = "BBB" class=""/>
<util:list id="AAA"/>
<bean id="AAAListMergeDirective" depends-on="AAA" 
parent="listMergeDirective" >
<property name="add" ref="BBB"  />
</bean>
Nani
  • 1
  • AFAIK "listMergeDirective" is a thing that exists only in SAP Commerce platform. It can't be used in "pure" Spring app. – Adam Badura Jun 29 '23 at 08:54