212

I'm using Spring to define stages in my application. It's configured that the necessary class (here called Configurator) is injected with the stages.
Now I need the List of Stages in another class, named LoginBean. The Configurator doesn't offer access to his List of Stages.

I cannot change the class Configurator.

My Idea:
Define a new bean called Stages and inject it to Configurator and LoginBean. My problem with this idea is that I don't know how to transform this property:

<property ...>
  <list>
    <bean ... >...</bean>
    <bean ... >...</bean>
    <bean ... >...</bean>
  </list>
</property>

into a bean.

Something like this does not work:

<bean id="stages" class="java.util.ArrayList">

Can anybody help me with this?

Betlista
  • 10,327
  • 13
  • 69
  • 110
guerda
  • 23,388
  • 27
  • 97
  • 146

13 Answers13

288

Import the spring util namespace. Then you can define a list bean as follows:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
                    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                    http://www.springframework.org/schema/util
                    http://www.springframework.org/schema/util/spring-util-2.5.xsd">


<util:list id="myList" value-type="java.lang.String">
    <value>foo</value>
    <value>bar</value>
</util:list>

The value-type is the generics type to be used, and is optional. You can also specify the list implementation class using the attribute list-class.

Adrián
  • 419
  • 2
  • 17
simonlord
  • 4,347
  • 1
  • 19
  • 12
  • 11
    and obviously the contents of the list can be values, references, and beans etc.. – simonlord Mar 10 '10 at 10:38
  • Wonderful answer, it's more "spring-like" – jpaoletti Aug 21 '13 at 22:46
  • Is it possible to somehow use references this way? – carlspring Mar 16 '14 at 00:22
  • 1
  • 2
    Hi I am getting this cvc-complex-type.2.4.c: The matching wildcard is strict, but no declaration can be found for element 'value'. I h ave added namespace and schemaLocation still – vishal May 06 '14 at 13:07
  • 19
    I just noticed that `@Autwired` doesn't help when injecting a list created this way. However, `@Resource` works. i.e. `@Resource List myList` – Matt Friedman May 28 '14 at 20:04
  • Is it possible to make this list lazy? It becomes relevant when it is a collection of "ref" elements to other beans. – Ivan Balashov Apr 16 '20 at 15:47
  • Thanks for the useful info above, and sorry if my question is slightly off the main topic here. What if I want to define "my-list" as an empty list and allow all later applications to insert refs (e.g. "foo", "bar", etc.) to "my-list" (meaning the content of the list is dynamic), is there a way to support this in Spring? Thanks – Liang Jun 06 '20 at 21:37
186

Here is one method:

<bean id="stage1" class="Stageclass"/>
<bean id="stage2" class="Stageclass"/>

<bean id="stages" class="java.util.ArrayList">
    <constructor-arg>
        <list>
            <ref bean="stage1" />
            <ref bean="stage2" />                
        </list>
    </constructor-arg>
</bean>
Betlista
  • 10,327
  • 13
  • 69
  • 110
stacker
  • 68,052
  • 28
  • 140
  • 210
  • 1
    +1 - I didn't know you could do that (though I can see that it should work). Suggestion: I think you should be able to embed the `StageClass` bean declarations in the `` avoiding the need for the `` elements. – Stephen C Mar 10 '10 at 12:33
  • 9
    you could also use util:list to give you an arraylist – Richard Aug 24 '11 at 10:33
  • Is it possible to embed those bean definitions into ""? – Sefler Jun 28 '12 at 04:05
  • @Sefler yes, the definitions should be identical there – eis Oct 07 '13 at 21:42
  • There is a pitfall: if using @Autowired, make sure that your pojo is also of type "ArrayList" and not just "List" or you could get something completely different. – Tilman Hausherr Oct 30 '19 at 13:41
42
<bean id="someBean" class="com.somePackage.SomeClass">
    <property name="myList">
        <list value-type="com.somePackage.TypeForList">
            <ref bean="someBeanInTheList"/>
            <ref bean="someOtherBeanInTheList"/>
            <ref bean="someThirdBeanInTheList"/>
        </list>
    </property>
</bean>

And in SomeClass:

class SomeClass {
    
    List<TypeForList> myList;
  
    @Required
    public void setMyList(List<TypeForList> myList) {
        this.myList = myList;
    }

}
Koray Tugay
  • 22,894
  • 45
  • 188
  • 319
  • if I understand correctly, this doesnt transform the list into a bean; but it just wraps the list inside a bean. right? – Nor.Z Apr 24 '22 at 05:29
40

Another option is to use JavaConfig. Assuming that all stages are already registered as spring beans you just have to:

@Autowired
private List<Stage> stages;

and spring will automatically inject them into this list. If you need to preserve order (upper solution doesn't do that) you can do it in that way:

@Configuration
public class MyConfiguration {
  @Autowired
  private Stage1 stage1;

  @Autowired
  private Stage2 stage2;

  @Bean
  public List<Stage> stages() {
    return Lists.newArrayList(stage1, stage2);
  }
}

The other solution to preserve order is use a @Order annotation on beans. Then list will contain beans ordered by ascending annotation value.

@Bean
@Order(1)
public Stage stage1() {
    return new Stage1();
}

@Bean
@Order(2)
public Stage stage2() {
    return new Stage2();
}
Jakub Kubrynski
  • 13,724
  • 6
  • 60
  • 85
9

Stacker posed a great answer, I would go one step farther to make it more dynamic and use Spring 3 EL Expression.

<bean id="listBean" class="java.util.ArrayList">
        <constructor-arg>
            <value>#{springDAOBean.getGenericListFoo()}</value>
        </constructor-arg>
</bean>

I was trying to figure out how I could do this with the util:list but couldn't get it work due to conversion errors.

Betlista
  • 10,327
  • 13
  • 69
  • 110
haju
  • 1,278
  • 4
  • 20
  • 38
  • this is so great... for using a "dictionary" java class instead of copying magic strings from the dictionary .. thank you!! – granadaCoder Dec 16 '20 at 16:50
4

I think you may be looking for org.springframework.beans.factory.config.ListFactoryBean.

You declare a ListFactoryBean instance, providing the list to be instantiated as a property withe a <list> element as its value, and give the bean an id attribute. Then, each time you use the declared id as a ref or similar in some other bean declaration, a new copy of the list is instantiated. You can also specify the List class to be used.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
3

Inject list of strings.

Suppose you have Countries model class that take list of strings like below.

public class Countries {
    private List<String> countries;

    public List<String> getCountries() {
        return countries;
    }   

    public void setCountries(List<String> countries) {
        this.countries = countries;
    }

}

Following xml definition define a bean and inject list of countries.

<bean id="demoCountryCapitals" name="demoCountryCapitals" class="com.sample.pojo.Countries">
   <property name="countries">
      <list>
         <value>Iceland</value>
         <value>India</value>
         <value>Sri Lanka</value>
         <value>Russia</value>
      </list>
   </property>
</bean>

Reference link

Inject list of Pojos

Suppose if you have model class like below.

public class Country {
    private String name;
    private String capital;
    .....
    .....
 }

public class Countries {
    private List<Country> favoriteCountries;

    public List<Country> getFavoriteCountries() {
        return favoriteCountries;
    }

    public void setFavoriteCountries(List<Country> favoriteCountries) {
        this.favoriteCountries = favoriteCountries;
    }

}

Bean Definitions.

 <bean id="india" class="com.sample.pojo.Country">
  <property name="name" value="India" />
  <property name="capital" value="New Delhi" />
 </bean>

 <bean id="russia" class="com.sample.pojo.Country">
  <property name="name" value="Russia" />
  <property name="capital" value="Moscow" />
 </bean>


 <bean id="demoCountryCapitals" name="demoCountryCapitals" class="com.sample.pojo.Countries">
  <property name="favoriteCountries">
   <list>
    <ref bean="india" />
    <ref bean="russia" />
   </list>
  </property>
 </bean>

Reference Link.

Hari Krishna
  • 3,658
  • 1
  • 36
  • 57
2
 <bean id="student1" class="com.spring.assin2.Student">  
<property name="name" value="ram"></property>  
<property name="id" value="1"></property> 
<property name="listTest">
        <list value-type="java.util.List">
            <ref bean="test1"/>
            <ref bean="test2"/>
        </list>
    </property>
</bean>  

define those beans(test1,test2) afterwards :)

RaM PrabU
  • 415
  • 4
  • 16
1

Use the util namespace, you will be able to register the list as a bean in your application context. You can then reuse the list to inject it in other bean definitions.

Juan Perez
  • 11
  • 1
1

As an addition to Jakub's answer, if you plan to use JavaConfig, you can also autowire that way:

import com.google.common.collect.Lists;

import java.util.List;

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Bean;

<...>

@Configuration
public class MyConfiguration {

    @Bean
    public List<Stage> stages(final Stage1 stage1, final Stage2 stage2) {
        return Lists.newArrayList(stage1, stage2);
    }
}
Jose Alban
  • 7,286
  • 2
  • 34
  • 19
1

You just remove id out of beans inside <list> tag. Like this:

<property name="listStaff">
  <list>
    <bean class="com.test.entity.Staff">
        <constructor-arg name="name" value = "Jonh"/>
        <constructor-arg name="age" value = "30"/>
    </bean>
    <bean class="com.test.entity.Staff">
        <constructor-arg name="name" value = "Jam"/>
        <constructor-arg name="age" value = "21"/>
    </bean>
  </list>
</property>
dqthe
  • 683
  • 5
  • 8
1

Use list-class attribute in util:list to make a standalone list of any particular type. for example if you want to make list of type ArrayList:

<util:list id="namesList" list-class="java.util.ArrayList" value-type="java.lang.String">
  <value>Abhay</value>
  <value>ankit</value>
  <value>Akshansh</value>
  <value>Db</value>
</util:list>

or if you want to make a list of type LinkedList then :

<util:list id="namesList" list-class="java.util.LinkedList" value-type="java.lang.String">
  <value>Abhay</value>
  <value>ankit</value>
  <value>Akshansh</value>
  <value>Db</value>
</util:list>
0

And this is how to inject set in some property in Spring:

<bean id="process"
      class="biz.bsoft.processing">
    <property name="stages">
        <set value-type="biz.bsoft.AbstractStage">
            <ref bean="stageReady"/>
            <ref bean="stageSteady"/>
            <ref bean="stageGo"/>
        </set>
    </property>
</bean>
Slava Babin
  • 708
  • 2
  • 12
  • 30