Basic bean creation has now been covered, but Spring also has specific bean support for Collections. There are list, set, map, and props elements. References to beans, value elements, and inner beans can be used to set values inside lists. So all the basic bean concepts learned earlier can be applied inside Collection specific elements.
The list element will create a list that can be injected into a constructor or property that takes a java.util.List.
Example 3.17. List Element
The first bean definition shows a List of Strings being set. The second bean definition shows a List of
Messages using references and an inner bean definition to create the list.
<bean id="stringMessageList"
class="org.springbyexample.springindepth.chapter03.collections.MessageContainer">
<property name="messageList">
<list>
<ref local="stringMessage01"/>
<ref local="stringMessage02"/>
<value>Spring is fun to learn.</value>
</list>
</property>
</bean>
<bean id="messageList"
class="org.springbyexample.springindepth.chapter03.collections.MessageContainer">
<property name="messageList">
<list>
<ref local="message01"/>
<ref local="message02"/>
<bean class="org.springbyexample.springindepth.bean.Message">
<property name="message" value="Spring is fun to learn." />
</bean>
</list>
</property>
</bean>
Example 3.18. List Factory
This example uses a FactoryBean to create a List directly as the bean instead of setting it as a property on another bean.
This way a bean can be created and inserted into multiple bean definitions.
<!-- String message factory list. -->
<bean id="messageFactoryList"
class="org.springframework.beans.factory.config.ListFactoryBean">
<property name="sourceList">
<list>
<ref bean="stringMessage01"/>
<ref bean="stringMessage02"/>
<value>Spring is fun to learn.</value>
</list>
</property>
</bean>
Example 3.19. List Util
Another custom namespace utility is for creating lists. The first bean definition is identical to the ListFactoryBean example
except it's a little shorter and easier to read. The second bean definition is the same except it uses the list-class attribute
to specify what List implementation to use. When the list-class attribute isn't used,
the ApplicationContext will choose the implementation class.
<util:list id="messageUtilList">
<ref bean="stringMessage01"/>
<ref bean="stringMessage02"/>
<value>Spring is fun to learn.</value>
</util:list>
<util:list id="messageUtilLinkedList"
list-class="java.util.LinkedList">
<ref bean="stringMessage01"/>
<ref bean="stringMessage02"/>
<value>Spring is fun to learn.</value>
</util:list>
The set element will create a java.util.Set that can be injected into a constructor or property.
Using a Set is identical to using a List except a Set will only have unique values. Since it is a Set,
multiple references to the same bean or beans that are equal will only keep one reference inside the Set.
Example 3.20. Set Element
<bean id="stringMessageSet"
class="org.springbyexample.springindepth.chapter03.collections.MessageContainer">
<property name="messageSet">
<set>
<ref local="stringMessage01"/>
<ref local="stringMessage02"/>
<value>Spring is fun to learn.</value>
</set>
</property>
</bean>
<bean id="messageSet"
class="org.springbyexample.springindepth.chapter03.collections.MessageContainer">
<property name="messageSet">
<set>
<ref local="message01"/>
<ref local="message02"/>
<bean class="org.springbyexample.springindepth.bean.Message">
<property name="message" value="Spring is fun to learn." />
</bean>
</set>
</property>
</bean>
Example 3.21. Set Factory
This example uses a FactoryBean to create a Set directly as a bean definition.
<bean id="messageFactorySet"
class="org.springframework.beans.factory.config.SetFactoryBean">
<property name="sourceSet">
<set>
<ref bean="stringMessage01"/>
<ref bean="stringMessage02"/>
<value>Spring is fun to learn.</value>
</set>
</property>
</bean>
Example 3.22. Set Util
The following example uses the util namespace to create a Set. The first bean definition is
the same as the SetFactoryBean example and the second definition uses the set-class attribute to have
the Set implementation be a java.util.TreeSet. Once again, if the set-class attribute isn't specified,
the ApplicationContext will choose the implementation.
<util:set id="messageUtilSet">
<ref bean="stringMessage01"/>
<ref bean="stringMessage02"/>
<value>Spring is fun to learn.</value>
</util:set>
<util:set id="messageUtilTreeSet"
set-class="java.util.TreeSet">
<ref bean="stringMessage01"/>
<ref bean="stringMessage02"/>
<value>Spring is fun to learn.</value>
</util:set>
The map element will create a java.util.Map that can be injected into a constructor or property.
The map element expects an entry element inside it to define key/value pairs for the Map.
There are a few different ways to create the entry element. One way is to have a value element,
ref element, or bean element nested inside the key element for the key or inside
the entry element for the value.
Creating beans this way is very verbose, but there are shortcut attributes on the entry element. The key attribute uses the attribute as a value and the key-ref uses the attribute value as a reference. Just like the ref attribute on the constructor-arg and property elements inside a bean definition, the key-ref attribute is equivalent to a ref element's bean attribute. There isn't a shortcut for the ref element's local attribute. There are also value and value-ref attributes with the same behavior as the key and key-ref attributes, but these obviously set the value for each entry.
Example 3.23. Map Element
The first bean definition injects a Map using String messages and
the second bean definition injects a Map of Message instances.
<bean id="stringMessageMap"
class="org.springbyexample.springindepth.chapter03.collections.MessageContainer">
<property name="messageMap">
<map>
<entry>
<key>
<value>1</value>
</key>
<ref local="stringMessage01"/>
</entry>
<entry key="2" value-ref="stringMessage02" />
<entry key-ref="key03" value="Spring is fun to learn." />
</map>
</property>
</bean>
<bean id="messageMap"
class="org.springbyexample.springindepth.chapter03.collections.MessageContainer">
<property name="messageMap">
<map>
<entry key="1" value-ref="message01" />
<entry key="2" value-ref="message02" />
<entry key-ref="key03">
<bean class="org.springbyexample.springindepth.bean.Message">
<property name="message" value="Spring is fun to learn." />
</bean>
</entry>
</map>
</property>
</bean>
Example 3.24. Map Factory
Example creating a Map as a bean definition using the MapFactoryBean.
<bean id="messageFactoryMap"
class="org.springframework.beans.factory.config.MapFactoryBean">
<property name="sourceMap">
<map>
<entry>
<key>
<value>1</value>
</key>
<ref bean="stringMessage01"/>
</entry>
<entry key="2" value-ref="stringMessage02" />
<entry key-ref="key03" value="Spring is fun to learn." />
</map>
</property>
</bean>
Example 3.25. Map Util
Another example using the util namespace with the second bean definition setting
the map-class attribute so it will us the java.util.TreeMap implementation.
<util:map id="messageUtilMap">
<entry>
<key>
<value>1</value>
</key>
<ref bean="stringMessage01"/>
</entry>
<entry key="2" value-ref="stringMessage02" />
<entry key-ref="key03" value="Spring is fun to learn." />
</util:map>
<util:map id="messageUtilTreeMap"
map-class="java.util.TreeMap">
<entry>
<key>
<value>1</value>
</key>
<ref bean="stringMessage01"/>
</entry>
<entry key="2" value-ref="stringMessage02" />
<entry key-ref="key03" value="Spring is fun to learn." />
</util:map>
The props element will create a java.util.Properties that can be injected into a constructor or property.
A property key/value pair can be added to the props element using the prop element.
The prop element is less flexible than the previous Collection elements that have been covered so far because
Properties only support a String for the key and value. The prop element has
a key attribute to set the key and inside the prop element the value can be specified.
Example 3.26. Props Element
The first bean definition shows creating a Properties instance using the props element.
The second bean definition shows a shortcut where Spring parses a String as if it was an external properties file.
Typically Spring always has well formed XML with discreet values either in attributes or elements. The shortcut could be nice
if you have an external file that you want to move into your Spring configuration or you may want to start with this in your Spring configuration
and later move it to a separate file if it grows larger.
<bean id="messageProperties"
class="org.springbyexample.springindepth.chapter03.collections.MessageContainer">
<property name="messageProperties">
<props>
<prop key="1">Spring is easy.</prop>
<prop key="2">Spring is useful.</prop>
<prop key="3">Spring is fun to learn.</prop>
</props>
</property>
</bean>
<bean id="messagePropertiesShortcut"
class="org.springbyexample.springindepth.chapter03.collections.MessageContainer">
<property name="messageProperties">
<value>
1=Spring is easy.
2=Spring is useful.
3=Spring is fun to learn.
</value>
</property>
</bean>
Example 3.27. Properties Factory
The PropertiesFactoryBean is used to create a bean that represents a java.util.Properties instance.
<bean id="messageFactoryProperties"
class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="properties">
<props>
<prop key="1">Spring is easy.</prop>
<prop key="2">Spring is useful.</prop>
<prop key="3">Spring is fun to learn.</prop>
</props>
</property>
</bean>
Example 3.28. Properties Util
This first bean definition uses util:properites to create an instance using information set on it and
the second uses util:properties to read from a properties file. The location attribute's value
will be resolved by the resource type of the default resource loader
the ApplicationContext uses. In the unit tests the default resource loader uses the classpath resource loader.
If this wasn't the default, setting the location to “classpath:/message.properties” would force the resource loader to use the classpath.
The different types of resource loaders available in Spring will be covered in more detail later.
<util:properties id="messageUtilProperties">
<prop key="1">Spring is easy.</prop>
<prop key="2">Spring is useful.</prop>
<prop key="3">Spring is fun to learn.</prop>
</util:properties>
<util:properties id="messageUtilFileProperties"
location="/message.properties"/>
Spring has Java 5 generics support for typed Collections. If the type expected by a Collection doesn't match,
Spring will try to convert any values to this type. For example if there is a List<Integer> and
a list element with a value of '3' is being injected into it, Spring will convert the '3' into an Integer so the list can be safely injected.
Example 3.29. Java5 Generics Typed Collection
The following example has a typed Map, but this applies to Lists and Sets also.
This example takes the previous bean definition Map example where the value is a Message instance and
sets it on the typedMessageMap property. The Map is set to have an Integer for the key
and a Message for the value.
/**
* Gets <code>Map<Integer, Message></code> of messages.
*/
public Map<Integer, Message> getTypedMessageMap() {
return typedMessageMap;
}
/**
* Sets <code>Map<Integer, Message></code> of messages.
*/
public void setTypedMessageMap(Map<Integer, Message> typedMessageMap) {
this.typedMessageMap = typedMessageMap;
}
When the values are injected, Spring will try to perform any type conversion it would for setting a standard property for a typed collection.
In this case the key is a String in the XML configuration, but is converted to an Integer as it is set.
No type conversion needs to be performed because the value is already a Message.
<bean id="typedMessageMap"
class="org.springbyexample.springindepth.chapter03.collections.MessageContainer">
<property name="typedMessageMap">
<map>
<entry key="1" value-ref="message01" />
<entry key="2" value-ref="message02" />
<entry key-ref="key03">
<bean class="org.springbyexample.springindepth.bean.Message">
<property name="message" value="Spring is fun to learn." />
</bean>
</entry>
</map>
</property>
</bean>
Spring has support has support for Java 5 enums and pre Java 5 type-safe emulated enums. Spring will automatically detect the enumeration class on the setter and use the text value from the property setting the enumeration to look up the appropriate enum to set on the class.
Example 3.30. Java 5 Enums
The following example shows a Fruit enum that has the values APPLE, ORANGE, and PEAR.
The FruitBasket class can have a Fruit enum set on it to indicate the type of fruit in the basket.
The bean definition creates a FruitBasket and sets the fruit property with the value 'APPLE'.
Spring looks up the matching enum value from the Fruit class and sets it on the property.
/**
* Enumeration of different types of fruit.
*/
public enum Fruit {
APPLE, ORANGE, PEAR
}
Excerpt from chapter03-collections/src/main/java/org/springbyexample/springindepth/chapter03/collections/FruitBasket.java
/**
* Sets fruit.
*/
public void setFruit(Fruit fruit) {
this.fruit = fruit;
}
Excerpt from chapter03-collections/src/main/resources/enum-applicationContext.xml
<bean id="fruitBasket"
class="org.springbyexample.springindepth.chapter03.collections.FruitBasket">
<property name="fruit" value="APPLE"/>
</bean>
Example 3.31. Pre Java 5 Type-Safe Enums
This is example is almost identical to the Java 5 enum example except before Java 5 enums didn't exist. The enum class used is a type-safe emulated enum.
It exposes type-safe constants on it representing different types of fruit and the constructor is private so no one can create other types of fruit for this class.
The only other way to do this before Java 5 was to just use int constants, but this isn't type-safe in any way.
Also any number could be passed into a method that takes an int.
/**
* Pre Java 5 type-safe enumeration of different types of fruit.
*/
public class OldFruit {
private String fruit = null;
public final static OldFruit APPLE = new OldFruit("apple");
public final static OldFruit ORANGE = new OldFruit("orange");
public final static OldFruit PEAR = new OldFruit("pear");
/**
* Private constructor.
*/
private OldFruit(String fruit) {
this.fruit = fruit;
}
...
}
Excerpt from chapter03-collections/src/main/java/org/springbyexample/springindepth/chapter03/collections/OldFruitBasket.java
/**
* Sets old fruit.
*/
public void setFruit(OldFruit fruit) {
this.fruit = fruit;
}
Excerpt from chapter03-collections/src/main/resources/enum-applicationContext.xml
<bean id="oldFruitBasket"
class="org.springbyexample.springindepth.chapter03.collections.OldFruitBasket">
<property name="fruit" value="APPLE"/>
</bean>