3.3 Constructor & Setter Injection

Spring gives a user the flexibility to define values and references a few of different ways. They are all basically the same, and where they differ slightly that will be explained. Single parameter constructor and setter injection bean definitions are the same except for the element they are configured on (constructor-arg vs. property). Setter injection can only have a single value set since Spring follows the JavaBeans specification (which only allows one value per getter/setter) when dealing with properties. Example configurations for the constructors and properties will be side by side for comparison in each example.

Example 3.2. By Value using the Value Attribute

The first bean definition uses the value attribute on the constructor-arg element to set the message, and the second bean definition uses the value attribute on the property element to set the message.

Excerpt from chapter03-constructors-setters/src/main/resources/constructor-applicationContext.xml
                
<bean id="messageAttributeValue"
           class="org.springbyexample.springindepth.chapter03.constructorsSetters.constructor.Message">
    <constructor-arg value="Spring comes before summer." />
</bean>
                
            
Excerpt from chapter03-constructors-setters/src/main/resources/setter-applicationContext.xml
                
<bean id="messageAttributeValue"
      class="org.springbyexample.springindepth.bean.Message">
    <property name="message" value="Spring comes before summer." />
</bean>
                
            

Example 3.3. By Value using the Value Element

These excerpts use the value element inside the constructor-arg and property elements to set the message. This is identical to the previous example once it's loaded by Spring into the IoC container. Using the value element is very useful if the text has a lot of characters to escape. Then the text could be put in a CDATA block (ex: <value><![CDATA[Spring message with unescaped characters: <>” ]]></value>). Using CDATA is only available inside elements, not in attributes. For anyone not very familiar with XML, CDATA is part of the XML specification and isn't any special processing built into Spring. Any XML parser will handle CDATA inside an element.

Excerpt from chapter03-constructors-setters/src/main/resources/constructor-applicationContext.xml
                
<bean id="messageElementValue"
           class="org.springbyexample.springindepth.chapter03.constructorsSetters.constructor.Message">
    <constructor-arg><value>Spring comes before summer.</value></constructor-arg>
</bean>
                
            
Excerpt from chapter03-constructors-setters/src/main/resources/setter-applicationContext.xml
                
<bean id="messageElementValue"
      class="org.springbyexample.springindepth.bean.Message">
    <property name="message"><value>Spring comes before summer.</value></property>
</bean>
                
            

Example 3.4. By Reference using the Ref Attribute

The following excerpts injects the message by reference into the constructor.

Excerpt from chapter03-constructors-setters/src/main/resources/constructor-applicationContext.xml
                
<bean id="springMessage" 
      class="java.lang.String">
    <constructor-arg value="Spring comes before summer." />
</bean>

<bean id="messageAttributeRef"
      class="org.springbyexample.springindepth.chapter03.constructorsSetters.constructor.Message">
    <constructor-arg ref="springMessage" />
</bean>
                
            
Excerpt from chapter03-constructors-setters/src/main/resources/setter-applicationContext.xml
                
<bean id="springMessage" 
      class="java.lang.String">
    <constructor-arg value="Spring comes before summer." />
</bean>

<bean id="messageAttributeRef"
      class="org.springbyexample.springindepth.bean.Message">
    <property name="message" ref="springMessage" />
</bean>
                
            

Example 3.5. By Reference using the Ref Element

These excerpts use the ref element. The ref element bean attribute is the same as the previous constructor-arg and property element's ref attribute. The bean attribute can reference another bean in any configuration file loaded into this ApplicationContext by id or name. The local attribute expects a reference to the id of a bean in the local configuration file. If it isn't found, an exception will be thrown. There isn't any way to specify a local bean reference using an attribute.

Excerpt from chapter03-constructors-setters/src/main/resources/constructor-applicationContext.xml
                
<bean id="springMessage" 
           class="java.lang.String">
    <constructor-arg value="Spring comes before summer." />
</bean>

...

<bean id="messageElementRefLocal"
           class="org.springbyexample.springindepth.chapter03.constructorsSetters.constructor.Message">
    <constructor-arg><ref local="springMessage"/></constructor-arg>
</bean>

<bean id="messageElementRefBean"
           class="org.springbyexample.springindepth.chapter03.constructorsSetters.constructor.Message">
    <constructor-arg><ref bean="springMessage"/></constructor-arg>
</bean>
                
            
Excerpt from chapter03-constructors-setters/src/main/resources/setter-applicationContext.xml
                
<bean id="springMessage" 
      class="java.lang.String">
    <constructor-arg value="Spring comes before summer." />
</bean>

...

<bean id="messageElementRefLocal"
      class="org.springbyexample.springindepth.bean.Message">
    <property name="message"><ref local="springMessage"/></property>
</bean>

<bean id="messageElementRefBean"
      class="org.springbyexample.springindepth.bean.Message">
    <property name="message"><ref bean="springMessage"/></property>
</bean>
                
            

Inner Beans

If you do need to make a bean that will only be injected in one place, there isn't a reason to have it defined separately. In this case an inner bean can be created inside the constructor-arg or property elements. The inner bean doesn't need an id attribute defined since it can't be referenced anywhere else. Even if the id or name attributes were defined, the container will ignore these values.

Example 3.6. Inner Bean

The first bean definition shows an inner bean being used as the constructor argument and the second bean definition shows the same inner bean being used for a property.

Excerpt from chapter03-constructors-setters/src/main/resources/constructor-applicationContext.xml
                    
<bean id="messageElementInnerBean"
      class="org.springbyexample.springindepth.chapter03.constructorsSetters.constructor.Message">
    <constructor-arg>
        <bean class="java.lang.String">
            <constructor-arg value="Spring comes before summer." />
        </bean>
    </constructor-arg>
</bean>
                    
                
Excerpt from chapter03-constructors-setters/src/main/resources/setter-applicationContext.xml
                    
<bean id="messageElementInnerBean"
      class="org.springbyexample.springindepth.bean.Message">
    <property name="message">
        <bean class="java.lang.String">
            <constructor-arg value="Spring comes before summer." />
        </bean>
    </property>
</bean>
                    
                

Setter Injection using the p-namespace

This is a shortcut for setter injection introduced in Spring 2.0. By defining the p-namespace on the root beans element, the namespace can be used with an attribute value that can be any property on the bean. For example, a property element with a name attribute value of 'message' could be changed to use the p-namespace. Then the property element could be removed and a p:message attribute could be added to the bean.

The p:message example can only be used to set a value on the message property. To inject a value by reference a '-ref' suffix must be added to the attribute name. Then p:message would become p:message-ref. While this reduces how verbose a bean definition can be, there is greater opportunity for typos when adding the '-ref' suffix. Creating unit tests could help find this issue, but the best solution is to use the Spring IDE in Eclipse. A typo using the p-namespace will show up as an error if it doesn't resolve to a valid property on the bean.

Using the p-namespace can help reduce how verbose bean definitions can become. Using a property element or the p-namespace are the exact same thing once the bean definition has been loaded. So it's really personal preference which one you use.

Example 3.7. Setter Injection using the p-namespace

The 'xmlns:p' attribute in the XML header represents the p-namespace. The first bean definition sets the message property with the attribute's value. The third and final definition sets the message property by reference. It makes a reference to the second bean definition.

chapter03-constructors-setters/src/main/resources/pnamespace-applicationContext.xml
                    
<?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:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- By Value -->
    <bean id="messageAttributeValue"
          class="org.springbyexample.springindepth.bean.Message"
          p:message="Spring comes before summer." />

    <!-- By Reference -->    
    <bean id="springMessage" 
          class="java.lang.String">
        <constructor-arg value="Spring comes before summer." />
    </bean>

    <bean id="messageAttributeRef"
          class="org.springbyexample.springindepth.bean.Message"
          p:message-ref="springMessage" />

</beans>
                    
                

Null and Empty Values

There may be times when you want to set a null value or an empty String (zero length) on a constructor or property. Doing either of these is very easy. There is a null element that can be specified as a value and using an empty value attribute or element will set an empty String.

Example 3.8. Null and Empty Values

The first bean definition explicitly sets null on the message property. The second bean definition explicitly sets a zero length String.

Excerpt from chapter03-constructors-setters/src/main/resources/value-applicationContext.xml
                    
<bean id="nullMessage"
      class="org.springbyexample.springindepth.bean.Message">
    <property name="message"><null/></property>
</bean>

<bean id="emptyMessage"
      class="org.springbyexample.springindepth.bean.Message">
    <property name="message"><value/></property>
</bean>
                    
                

Nested Properties

Spring has full support for nested properties (sometimes called compound properties) as defined in the JavaBean specification. Properties can get and set values of beans inside other beans. For example, a bean that has a person bean with a firstName property can be referenced using a nested property path of 'person.firstName'. There isn't a limit to the number of levels you can keep calling nested properties. The only limitation is that each value retrieved must not be null or when the getter or setter is called on that bean, otherwise there will be a NullPointerException. Nested properties can also be used to access values in a List or Map.

Typically nested properties are used more often for retrieving a value than setting one. If there was a person bean that had an Address instance as part of the bean, it would make sense to use nested properties to set the value. But it would be much better to let Spring instantiate the Address instance as an address bean and then inject it into the person bean.

One area that regularly uses nested properties to retrieve and set values are fields on JSP in a web application. A field on an HTML form can be bound to a nested property. Spring will use the nested property to display the nested property's value in the HTML and also to set the incoming value back on the bean.

Example 3.9. Nested Properties

The following example shows a bean with a reference to the Message JavaBean inside it. The property name of 'messageBean.message' is the same as calling getMessageBean().setMesssage(“Spring comes before summer.”) on an instance of NestedMessageContainer.

Excerpt from chapter03-constructors-setters/src/main/resources/nested-setter-applicationContext.xml
                    
<bean id="nestedMessage"
      class="org.springbyexample.springindepth.chapter03.constructorsSetters.NestedMessageContainer">
    <property name="messageBean.message" value="Message number one." />
</bean>
                    
                

Nested Collections

The following examples show setting values this way, but it's better to use Spring's collection elements, factories, and utilities when setting these values. The first bean definition sets values on a List, but this works for arrays and Lists. Immediately after the property name, the index of the list the value should set on is set inside brackets. Arrays and lists start at zero just like programming with them in Java. Spring does not automatically make a list larger so an exception will occur if you try to set a value outside the range of the array. The second example shows setting values on a Map. The key used when setting the value on the Map is the text inside the brackets that follow the property name.

Excerpt from chapter03-constructors-setters/src/main/resources/nested-setter-applicationContext.xml
                        
<bean id="arrayMessage"
      class="org.springbyexample.springindepth.chapter03.constructorsSetters.MessageNestedContainer">
    <property name="messages[0]" value="Message number one." />
    <property name="messages[1]" value="Message number two." />
    <property name="messages[2]" value="Message number three." />
</bean>

<bean id="mapMessage"
      class="org.springbyexample.springindepth.chapter03.constructorsSetters.MessageNestedContainer">
    <property name="messageMap[one]"   value="Message number one." />
    <property name="messageMap[two]"   value="Message number two." />
    <property name="messageMap[three]" value="Message number three." />
</bean>
                        
                    

PropertyPathFactoryBean

Using beans created in the previous nested properties examples, the PropertyPathFactoryBean can be used to retrieve a nested property from them and create a bean. FactoryBeans in general will be discussed more later, but they let you create a bean instance different from the one specified by the bean element's class attribute. The id/name of the bean is the nested property path used by the factory bean. Notice in the second bean definition that the name attribute of the bean element is used instead of the id attribute. The bracket characters in the array and Map nested properties aren't valid characters for an XML ID, but as mentioned in the bean naming section the name attribute can be used when there is a need to use characters naming a bean that aren't valid for an XML ID.

The third bean definition shows using the targetBeanName and propertyPath properties so the id can be given a name other than the actual nested property path. The PropertyPathFactoryBean also has a targetObject property that isn't used in the example bean definitions. This property allows you to use an inner bean instead using a bean by reference.

Excerpt from chapter03-constructors-setters/src/main/resources/nested-setter-applicationContext.xml
                        
<bean id="nestedMessage.messageBean.message" 
      class="org.springframework.beans.factory.config.PropertyPathFactoryBean"/>

<bean name="arrayMessage.messages[0]" 
      class="org.springframework.beans.factory.config.PropertyPathFactoryBean"/>

<bean id="nestedMapFactoryMessage" 
      class="org.springframework.beans.factory.config.PropertyPathFactoryBean">
    <property name="targetBeanName" value="mapMessage" />
    <property name="propertyPath" value="messageMap[one]" />
</bean>
                        
                    

Util Namespace

In Spring 2.0 being able to create custom namespaces was introduced. The default ones that come with Spring are AOP, Context, Java EE, JMS, Dynamic Languages, Tools, Transactions, and Utils. Creating your own custom namespace and most of the default namespaces will be covered later, but we will start covering the util namespace now.

One of the utilities is for creating beans based using nested properties. Each of these example identical to the PropertyPathFactoryBean examples. Notice that to add another namespace the 'xmlns:util' line was added and also the util schema locations to the root beans element. Whatever value is declared after the 'xmlns:' will be used as the reference for this namespace. So you could always name it differently, but it will be less confusing when following examples if the standard naming conventions from the Spring documentation is followed.

The schema location for the util namespace was also added to the 'xsi:schemaLocation' attribute. The URL 'http://www.springframework.org/schema/util' will be used by Spring to look up the namespace handler. The namespace handler will be used to parse the custom namespace and register beans from it. The URL 'http://www.springframework.org/schema/util/spring-util-2.0.xsd' is the schema location of the XSD. XML Editors will use this to retrieve the XSD from the URL to provide validation when editing the XML. Spring will try to retrieve the XSDs from inside it's jars when loading and validating the XML configuration files. The Spring IDE also registers these local copies with Eclipse so they don't need to be downloaded from the URL each time.

Excerpt from chapter03-constructors-setters/src/main/resources/nested-setter-applicationContext.xml
                        
<?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.xsd
                        http://www.springframework.org/schema/util
                        http://www.springframework.org/schema/util/spring-util-2.0.xsd">

...

    <util:property-path id="nestedMessageUtil" path="nestedMessage.messageBean.message"/>

    <util:property-path id="nestedArrayMessageUtil" path="arrayMessage.messages[0]"/>

    <util:property-path id="nestedMapMessageUtil" path="mapMessage.messageMap[one]"/>

</beans>
                        
                    

IDREF Element

The idref element can be used to reference a bean name. The earlier example using the PropertyPathFactoryBean set the property targetBeanName, but there isn't any validation done to check if the bean name given to the property is good until the bean is processed. If a bean has a scope of prototype or it is lazily initialized, then the bean may not be initialized when the ApplicationContext is started. In that case, a typo could cause a failure in the application at some later point. To avoid this the idref element can be used. It has a bean and local attribute just like the ref element. Just like the ref element the local attribute can only refer to beans in the local XML configuration file. The bean attribute will be validated when the ApplicationContext is processed and the local attribute will also be validated by the XML parser.

Example 3.10. Bad Bean Name Reference

The following example shows a failure because of a bad bean name. The bean's scope is set to prototype so there isn't an error until the bean is referenced in the unit test and the context tries to instantiate this bean for the first time. The prototype scope creates a new instance every time the bean is referenced. The value 'badNestedMessage' set on the targetBeanName property is a reference to a bean name that doesn't exist.

Excerpt from chapter03-constructors-setters/src/main/resources/idref-applicationContext.xml
                    
<bean name="nestedFactoryMessage" 
      class="org.springframework.beans.factory.config.PropertyPathFactoryBean"
      scope="prototype">
    <property name="targetBeanName" value="badNestedMessage" />
    <property name="propertyPath" value="messageBean.message" />
</bean>
                    
                

Example 3.11. IDREF Element

In these bean definitions the idref element is used to set the targetBeanName property on the PropertyPathFactoryBean.

Excerpt from chapter03-constructors-setters/src/main/resources/idref-applicationContext.xml
                    
<bean name="nestedIdrefLocalMessage" 
      class="org.springframework.beans.factory.config.PropertyPathFactoryBean">
    <property name="targetBeanName">
        <idref local="nestedMessage"/>
    </property>
    <property name="propertyPath" value="messageBean.message" />
</bean>

<bean name="nestedIdrefBeanMessage" 
      class="org.springframework.beans.factory.config.PropertyPathFactoryBean">
    <property name="targetBeanName">
        <idref bean="nestedMessage"/>
    </property>
    <property name="propertyPath" value="messageBean.message" />
</bean>
                    
                

Static Bean References

Spring has some utilities and FactoryBeans to create beans that reference static fields and methods. Although Spring can easily access static methods to retrieve an instance from a singleton class, it's better to let Spring handle singleton creation using a bean's default singleton scope. Of course you may need to create bean in Spring that follows the singleton design pattern because of legacy code or 3rd party libraries.

Example 3.12. Bean Creation from a Static Field

The FieldRetrievingFactoryBean can be used to create a bean from a static field. The FieldRetrievingFactoryBean can also be used to create a reference to a non-static field, but this isn't covered here. The first bean definition references a static field defining a message bean. The second one uses a shortcut where the id attribute of the bean is used to reference the static field.

Excerpt from chapter03-static-bean-references/src/main/resources/applicationContext.xml
                    
<bean id="message" 
      class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
    <property name="staticField" value="org.springbyexample.springindepth.chapter03.staticBeanReferences.Constants.MESSAGE"/>
</bean>

<bean id="org.springbyexample.springindepth.chapter03.staticBeanReferences.Constants.MESSAGE"
      class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean"/>                    
                    
                

The following bean definitions use the util namespace's constant element to do the exact same thing as directly using the FieldRetrievingFactoryBean. The second bean definition will use the static-field attribute as the id since the id attribute isn't set explicitly.

Excerpt from chapter03-static-bean-references/src/main/resources/util-applicationContext.xml
                    
<util:constant id="message" 
               static-field="org.springbyexample.springindepth.chapter03.staticBeanReferences.Constants.MESSAGE" />

<util:constant static-field="org.springbyexample.springindepth.chapter03.staticBeanReferences.Constants.MESSAGE" />                    
                    
                

Example 3.13. Bean Creation from a Singleton Class

The standard Message class has been modified slightly to make it into a singleton. The constructor is now private and there is a static getInstance() method to get an instance of the class. This class follows the classic singleton design pattern.

chapter03-static-bean-references/src/main/java/org/springbyexample/springindepth/chapter03/staticBeanReferences/Message.java
                    
package org.springbyexample.springindepth.chapter03.staticBeanReferences;

/**
 * Message bean.
 */
public class Message {

    private static Message messageInstance = new Message();

    protected String message = "Message number one.";

    /**
     * Private constructor for singleton.
     */
    private Message() {}

    public static Message getInstance() {
        return messageInstance;
    }

    /**
     * Gets message.
     */
    public String getMessage() {
        return message;
    }

    /**
     * Sets message.
     */
    public void setMessage(String message) {
        this.message = message;
    }

}
                    
                

The MethodInvokingFactoryBean can be used to create a bean referring to a static method. It has a staticMethod property to set, so when the FactoryBean interface's getObject() is called it dynamically runs Message.getInstance(). The value should be the full package, class, and method name. The returned Message instance is then associated as the message bean in the IoC container.

Excerpt from chapter03-static-bean-references/src/main/resources/applicationContext.xml
                    
<bean id="message" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    <property name="staticMethod">
        <value>org.springbyexample.springindepth.chapter03.staticBeanReferences.Message.getInstance</value>
    </property>
</bean>