Suppose I have a class MyClass which can be instantiated either with String or it have predefined static instances inside a class.
Something like this:
public class MyClass {
public final static MyClass A = new MyClass("A");
public final static MyClass B = new MyClass("B");
public final static MyClass C = new MyClass("C");
...
public MyClass(String name) {
...
}
}
Is it possible to create an ArrayList<MyClass> bean in Spring config somehow? Something like
<bean id="sequence" class="...ArrayList">
<member class="...MyClass" value="A"/>
<member ... />
....
</bean>
UPDATE 1
Is it possible to write following way:
<bean id="sequence" class="...ArrayList">
<constructor-arg>
<list>
<bean class="...MyClass" constructor-arg="A"/>
<bean class="...MyClass" constructor-arg="B"/>
<bean class="...MyClass" constructor-arg="C"/>
</list>
</constructor-arg>
</bean>
You should have a look at the Collections section in the spring IOC documentation.
<bean id="moreComplexObject" class="example.ComplexObject">
<property name="someList">
<list>
<value>a list element followed by a reference</value>
<ref bean="myDataSource" />
</list>
</property>
</bean>
You could do:
<bean id="myClassA" class="org.foo.MyClass">
<constructor-arg>
<bean class="java.lang.String">
<constructor-arg value="A"/>
</bean>
<constructor-arg>
</bean>
<bean id="sequence" class="java.util.ArrayList">
<constructor-arg>
<list>
<ref bean="myClassA" />
...
</list>
</constructor-arg>
</bean>
Note, however, that the most common approach is to inject a list directly into a bean rather than wrapping a list within a list first.
Yes. You can even create it as a standalone bean. See this thread for two examples.
Related
Consider this simple example -
public class Person
{
private String name;
private Date dateOfBirth;
// getters and setters here...
}
In order to initialize Person as a Spring bean, I can write the following.
<bean id = "Michael" class = "com.sampleDomainName.Person">
<property name = "name" value = "Michael" />
</bean>
But in the above bean definition, how can I set the dateOfBirth?
For eg. I want to set the dateOfBirth as
1998-05-07
Treat it like any other POJO (which is is)
<property name="dateOfBirth">
<bean class="java.util.Date" />
</property>
If you need to use an explicit value (such as 1975-04-10), then simply call one of the other constructors (although those which take year-month-day are deprecated). You could also use an explicit java.beans.PropertyEditor which Spring rolls with already (see section 6.4.2; note that you can write your own editors and register them for your own types). You need to register the CustomEditorConfigurer in your config:
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="java.util.Date"
value="org.springframework.beans.propertyeditors.CustomDateEditor"/>
</map>
</property>
</bean>
Then your data looks like:
<property name="dateOfBirth" value="1975-04-10" />
I might add that Date is not an appropriate data type to store a date-of-birth because Date is really an instant-in-time. You might like to look at Joda and use the LocalDate class.
One of the answers mentioned here is useful, but it needs additional information. The constructor arguments for the CustomDateEditor need to be supplied.
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="java.util.Date"> <ref local = "customDateEditor" />
</entry>
</map>
</property>
</bean>
<bean id = "customDateEditor" class="org.springframework.beans.propertyeditors.CustomDateEditor">
<constructor-arg>
<bean class="java.text.SimpleDateFormat">
<constructor-arg value="yyyy-MM-dd" />
</bean>
</constructor-arg>
<constructor-arg value="true" />
</bean>
Now we can do
<property name="dateOfBirth" value="1998-05-07" />
Spring inject Date into bean property – CustomDateEditor
This paper give two suggestions:
Factory bean
CustomDateEditor
I suggest the "Factory Bean" because the CustomDateEditor is not supported in Spring 4.0+ and the Factory Bean is easy enough to use.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="dateFormat" class="java.text.SimpleDateFormat">
<constructor-arg value="yyyy-MM-dd" />
</bean>
<bean id="customer" class="com.mkyong.common.Customer">
<property name="date">
<bean factory-bean="dateFormat" factory-method="parse">
<constructor-arg value="2010-01-31" />
</bean>
</property>
</bean>
</beans>
Use a CustomDateEditor. It's been in Spring since the early days.
i am trying to develop a Spring bean like this
<bean id="id" class="java.util.ArrayList" scope='prototype'>
<constructor-arg>
<list>
<bean class='MyClass'>
<property name='id' value='1313'/>
<property name="name" value='John Lennon'/>
<property name='wifes'>
<list>
<bean class="WifeClazz">
<constructor-arg index='0' value='Cynthia Lennon'/>
<constructor-arg index='1'>
<list><value>1962</value><value>1968</value></list>
</constructor-arg>
</bean>
</list>
</property>
</bean>
</list>
</constructor-arg>
</bean>
this is just a example the WifeClazz the name is just for the example.. have a Constructor which have a String and a series of Integers.. like this example
new WifeClazz("Cinthia Lennon",java.util.Arrays.asList(1,2,3,4,5,6,7,8));
the integers may be a severals from 1 to 10 integers.
but i think is kind of annoying do something like this
<constructor-arg index='1'>
<list>
<value>1</value>
<value>2</value>
<value>3</value>
<value>4</value>
</list>
</constructor-arg>
would be great if i could do something like this
<constructor-arg index='1'>
<value>#{T(java.util.Arrays).asList(1,2,3,4)}</value>
</constructor-arg>
but throws Exception any clue?
any help is hugely appreciate.
UPDATE
I have change my code according Edwin a something like this.
<constructor-arg index="1" type="java.util.Collection" value="#{T(java.util.Arrays).asList(1,2,3,4,5)}"/>
but throws
Caused by: java.lang.IllegalArgumentException: Final expected argument should be array type (the varargs parameter)
my target clazz is
public MyClass(final String name,final List<Integer>years){}
my resulting code
<bean id="id" class="java.util.ArrayList" scope='prototype'>
<constructor-arg>
<list>
<bean class='MyClass'>
<property name='id' value='1313'/>
<property name="name" value='John Lennon'/>
<property name='wifes'>
<list>
<bean class="WifeClazz">
<constructor-arg index='0' value='Cynthia Lennon'/>
<constructor-arg index="1" type="java.util.Collection" value="#{T(java.util.Arrays).asList(1,2,3,4,5)}"/>
</bean>
</list>
</property>
</bean>
</list>
</constructor-arg>
</bean>
this solves the trick...
<constructor-arg index='1' type="java.util.List" value="#{{1,2,3,4,5}}"/>
This works for me
<bean id="list" class="java.util.ArrayList">
<constructor-arg index="0" value="#{T(java.util.Arrays).asList(1,2,3,4,5)}"/>
</bean>
To disambiguate constructors, this also works for me
<bean id="list" class="java.util.ArrayList">
<constructor-arg type="java.util.Collection" value="#{T(java.util.Arrays).asList(1,2,3,4,5)}"/>
</bean>
You can also use a collection SPeL, like this, and avoid having to use Arrays.asList directly.
<bean id="list" class="java.util.ArrayList">
<constructor-arg type="java.util.Collection" value="#{{1,2,3,4,5}}"/>
</bean>
How can I configure list of java.util.Locale in Spring XML?
This is what I tried (which obviously didn't work..):-
<bean
class="x.y.z.CommandBean"
scope="prototype">
<property name="locales">
<list value-type="java.util.Locale">
<value>Locale.US</value>
<value>Locale.FR</value>
</list>
</property>
</bean>
Exception :-
org.springframework.beans.TypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'java.util.Locale';
Also, is there any way I can move the locale as comma separated values in a .properties file?
Try this,
<property name="locales">
<list value-type="java.util.Locale">
<value>java.util.Locale.US</value>
<value>java.util.Locale.FR</value>
</list>
</property>
In your class,
private List<Locale> locales;
public List<Locale> getLocales() {
return locales;
}
public void setLocales(List<Locale> locales) {
this.locales = locales;
}
Specifying the values as
<value>java.util.Locale.US</value>
<value>java.util.Locale.FR</value>
should do the trick. Getting them from a properties value seems a bit more work.
You could specify them like
my.app.locales=en_US,de_DE
configuring
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>file:./config.properties</value>
</property>
</bean>
<bean
class="x.y.z.CommandBean"
scope="prototype">
<property name="locales">
<bean class="org.springframework.util.StringUtils" factory-method="tokenizeToStringArray">
<constructor-arg type="java.lang.String" value="${my.app.locales}"/>
<constructor-arg type="java.lang.String" value=","/>
</bean>
</property>
</bean>
and then you would need
import org.apache.commons.lang3.LocaleUtils;
public void setLocales(String[] localeStrings) {
List<Locale> locales = new ArrayList<Locale>(localeStrings.length);
for (String localeName: Arrays.asList(localeStrings)) {
locales.add(LocaleUtils.toLocale(localeName));
}
this.locales = locales;
}
this is a bit gludgy though. As an alternative, you could define a wrapper class that does the conversion above, and wire that as a bean. Then hook your class to that bean.
A collection object can be created from another collection object using constructor.
List<Student> list = new ArrayList<Student>(someStudentList);
Which can be done in Spring.
<bean id="stdArrayList" class="java.util.ArrayList">
<constructor-arg >
<list>
<ref bean="student1" />
<ref bean="student2" />
<ref bean="student3" />
</list>
</constructor-arg>
</bean>
<bean id="student1" class="mawia.test.Student"
....
How can I do this way of adding item in Spring?
Set<Student> set= new TreeSet<Student>();
set.add(new Student(5, "Mawia"));
...
So that I can use the constructor which accept a comparator object.
Set<Student> set= new TreeSet<Student>(new MyComparator());
set.add(new Student(5, "Mawia"));
...
I suspect the simplest approach would be to create a trivial subclass of TreeSet that provides a two-argument constructor:
public class MyTreeSet<T> extends TreeSet<T> {
public MyTreeSet(Comparator<? super T> cmp, Collection<? extends T> coll) {
super(cmp);
addAll(coll);
}
}
and use this as the type of your bean, passing both the comparator and the initial values as <constructor-arg> values.
<bean id="studentSet" class="com.example.MyTreeSet">
<constructor-arg index="0">
<bean class="com.example.MyComparator" />
</constructor-arg>
<constructor-arg index="1">
<list>
<ref bean="student1" />
<ref bean="student2" />
<ref bean="student3" />
</list>
</constructor-arg>
</bean>
Or instead of a subclass of TreeSet you could write your own FactoryBean.
To do it without writing any additional code you could use a second bean definition to do the adding
<bean id="studentSet" class="java.util.TreeSet">
<constructor-arg>
<bean class="com.example.MyComparator" />
</constructor-arg>
</bean>
<bean id="studentSetFiller" factory-bean="studentSet" factory-method="addAll">
<constructor-arg>
<list>
<ref bean="student1" />
<ref bean="student2" />
<ref bean="student3" />
</list>
</constructor-arg>
</bean>
but then any other bean into which you inject studentSet needs an additional depends-on="studentSetFiller" to make sure the set is populated before the target bean tries to use it.
You might be able to do it using the util schema like this;
<util:set id="emails" set-class="java.util.TreeSet">
<value>pechorin#hero.org</value>
<value>raskolnikov#slums.org</value>
<value>stavrogin#gov.org</value>
<value>porfiry#gov.org</value>
</util:set>
(taken from http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/xsd-config.html#xsd-config-body-schemas-util-set)
I'll test if its possible to add constructor args and confirm.
The TreeSet does not provide a combined constructor to pass Comparator as well as data. So I guess you can only do one via construtor injection.
Other part you should try via property injection if its exposed.
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?
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.
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>
<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;
}
}
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();
}
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.
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.
<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 :)
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.
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.
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);
}
}
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>
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>
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>