JBoss.org Community Documentation

11.1. Using values

Once a POJO instance has been created then it can be configured by injecting property values. Like most other features this can be done using either annotations or a deployment descriptor. For each property that you wish to inject the bean must define an appropriate setter method for the microcontainer to call.


public class PropertiesBean {

    public void setTitle(@StringValue("JBoss Microcontainer") String title) {
        ...
   }

    public void setLink(@StringValue("http://www.jboss.org") URL link) {
        ...
    }

    public void setNumber(@StringValue("4") int number) {
        ...
    }
}

<bean name="PropertiesBean" class="org.jboss.example.microcontainer.properties.PropertiesBean">
    <property name="title">JBoss Microcontainer</property>
    <property name="link">http://www.jboss.org</property>
    <property name="number">4</property>
</bean> 

As you have probably noticed we are required to enter all of our values as strings since we are dealing with text files. These strings are converted into objects of the correct type using JavaBean PropertyEditors. If the property takes an interface or abstract class then you can pass a specific implementation using a type or class attribute depending on whether you're using annotations or XML.


public class PropertiesBean {
    public void setNumber(@StringValue(value="4", type="java.lang.Long") Number number) {
        ...
   }
}

<bean name="PropertiesBean" class="org.jboss.example.microcontainer.properties.PropertiesBean">
    <property name="number" class="java.lang.Long">4</property>
</bean> 

Sometimes you may want to pass in a value that isn't of the same type as the property but can be progressed into it. Progression is typically used for converting numbers from one type to another, e.g. Short to Int or Float to Double. JBoss Microcontainer by default will automatically perform progression using a SimpleProgressionConverter implementation.


<bean name="SimpleBean" class="org.jboss.test.SimpleBean">
    <property name="anInt">
        <javabean xmlns="urn:jboss:javabean:2.0" class="java.lang.Double">
            <constructor>
                <property name="aDouble">123.456</property>
            </constructor>
        </javabean>
    </property>
    <property name="aShort">
        <javabean xmlns="urn:jboss:javabean:2.0" class="java.lang.Float">
            <constructor>
                <property name="aFloat">987.6543</property>
            </constructor>
        </javabean>
    </property>
    <property name="aFloat">
        <javabean xmlns="urn:jboss:javabean:2.0" class="java.lang.Integer">
            <constructor>
                <property name="anInt">314159</property>
            </constructor>
        </javabean>
    </property>
</bean>

You can replace the default progression converter implementation with one of your own by setting the org.jboss.reflect.plugins.progressionConverter system property using a fully-qualified class name. If you want to prevent progression from occuring altogether then you can use the NullProgressionConverter which is also provided.

-Dorg.jboss.reflect.plugins.progressionConverter=org.jboss.reflect.plugins.NullProgressionConvertor

If you want to use a null value then you need to use the @NullValue annotation or <null/> element. This is so we can differentiate it from the string 'null'.


public void setTitle(@NullValue String title) {
    ...
} 

<bean name="PropertiesBean" class="org.jboss.example.microcontainer.properties.PropertiesBean">
    <property name="title"><null/></property>
</bean> 

Similarly if you want to refer to the current object then you should use the @ThisValue annotation or <this/> element.


public void setObject(@ThisValue Object target) {
    ...
} 

<bean name="PropertiesBean" class="org.jboss.example.microcontainer.properties.PropertiesBean">
    <property name="target"><this/></property>
</bean> 

Property values can also be defined using a longer form of XML if you prefer.


<bean name="PropertiesBean" class="org.jboss.example.microcontainer.properties.PropertiesBean">
    <property name="number">
        <value class="java.lang.Long">4</value>
    </property>
</bean> 

This is primarily used when configuring values representing collections such as lists, sets and arrays. Elements of a collection are defined by listing annotations or nesting <value> elements as follows:


@CollectionValue(elementClass="java.lang.String",
                 {@Value(string=@StringValue("string1")),
                  @Value(string=@StringValue("string2")),
                  @Value(string=@StringValue("string3")),
                  @Value(string=@StringValue("string4"))})
public void setCollection(Collection collection) {
    ...
} 

<bean name="SimpleBean" class="org.jboss.example.SimpleBean">
    <property name="collection">
        <collection elementClass="java.lang.String">
            <value>string1</value>
            <value>string2</value>
            <value>string3</value>
            <value>string4</value>
       </collection>
    </property>
</bean> 

The elementClass attribute specifies the default class for the values. This can be overriden for individual values using the type or class attributes.


@CollectionValue(elementClass="java.lang.String",
                 {@Value(string=@StringValue("string1")),
                  @Value(string=@StringValue("string2")),
                  @Value(string=@StringValue(value="3.0", type="java.lang.Float")),
                  @Value(string=@StringValue(value="4", type="java.lang.Integer"))})
public void setCollection(Collection collection) {
    ...
} 

<bean name="SimpleBean" class="org.jboss.example.SimpleBean">
    <property name="collection">
        <collection elementClass="java.lang.String">
            <value>string1</value>
            <value>string2</value>
            <value class="java.lang.Float">3.0</value>
            <value class="java.lang.Integer">4</value>
       </collection>
    </property>
</bean> 

Warning

The type of each value must be specified using either the elementClass or type/class attribute in order for the collection to be created.

Lists, sets and arrays take the same form as the collection annotation and XML element.


@ListValue(elementClass="java.lang.String",
           {@Value(string=@StringValue("my first string")),
            @Value(string=@StringValue("my second string"))})
public void setList(List list) {
    ...
}

@SetValue(elementClass="java.lang.Integer",
          {@Value(string=@StringValue("50")),
           @Value(string=@StringValue("55"))})
public void setSet(Set set) {
    ...
}

@ArrayValue(elementClass="java.lang.Float",
            {@Value(string=@StringValue("1.0")),
             @Value(string=@StringValue("2.0"))})
public void setArray(Object[] array) {
    ...
} 

<bean name="SimpleBean" class="org.jboss.example.SimpleBean">
    <property name="list">
        <list elementClass="java.lang.String">
            <value>my first string</value>
            <value>my second string</value>
        </list>
    </property>

    <property name="set">
        <set elementClass="java.lang.Integer">
            <value>50</value>
            <value>55</value>
        </set>
    </property>

    <property name="array">
        <array elementClass="java.lang.Float">
            <value>1.0</value>
            <value>2.0</value>
        </array>
    </array>
</bean> 

They can even be nested within one another if required.


@ListValue(elementClass="java.lang.String",
           {@Value(string=@StringValue("my first string")),
            @Value(string=@SetValue(elementClass="java.lang.Integer",
                                    {@Value(string=@StringValue("1")),
                                     @Value(string=@StringValue="2"))})
                  )})
public void setList(List list) {
    ...
}

<bean name="SimpleBean" class="org.jboss.example.SimpleBean">
    <property name="list">
        <list elementClass="java.lang.String">
            <value>my first string</value>
            <value>
                <set elementClass="java.lang.Integer">
                    <value>1</value>
                    <value>2</value>
                </set>
            </value>
        </list>
    </property>
</bean>

Maps can also be created using multiple entries of key/value pairs. As we now have two types to consider we must use the keyClass and valueClass attributes to specify the default classes for each entry. Again these can be overriden for individual entries if necessary.


@MapValue(keyClass="java.lang.String",
          valueClass="java.lang.String",
          {@EntryValue(key=@Value(string=@StringValue("foo.bar.key")),
                       value=@Value(string=@StringValue("QWERT"))),
           @EntryValue(key=@Value(string=@StringValue("xyz.key")),
                       value=@Value(string=@StringValue("QWERTY")))
          })
public void setMap(Map<String, String> map) {
    ...
} 

<bean name="SimpleBean" class="org.jboss.example.SimpleBean">
    <property name="map">
        <map keyClass="java.lang.String" valueClass="java.lang.String">
            <entry>
                <key>foo.bar.key</key>
                <value>QWERT</value>
            </entry>
            <entry>
                <key>xyz.key</key>
                <value>QWERTY</value>
            </entry>
        </map>
    </property>
</bean> 

So far we have defined collections, lists, sets, arrays and maps but all of these have multiple implementations, e.g. java.util.ArrayList, java.util.LinkedList, so which are we using at runtime? By default JBoss Microcontainer will look for an existing instance using the corresponding getter method for the property. If one is found then it is used. If not then the type of the property is analysed and providing that it represents a class (not an interface) then this is used to create a new instance. Failing that a default instance will be created as follows:

If you want to override this behaviour and specify your own class then you can simply add a clazz attribute to your annotation or class attribute to your XML element containing the fully-qualified class name. This causes the microcontainer to create a new instance using the specified class.


@SetValue(clazz="java.util.TreeSet",
          elementClass="java.lang.Integer",
          {@Value(string=@StringValue("50")),
           @Value(string=@StringValue("55"))})
public void setSet(Set set) {
    ...
}

<bean name="SimpleBean"
 class="org.jboss.example.SimpleBean">
    <property name="set">
        <set class="java.util.TreeSet" elementClass="java.lang.Integer">
            <value>50</value>
            <value>55</value>
        </set>
    </property>
</bean> 

Note

If you don't specify a clazz /class attribute but you want to ensure that a new instance is created then you can prevent the microcontainer from looking for a existing instance by specifying a preinstantiate attribute in the <property> element. Currently this cannot be achieved using annotations.


<bean name="SimpleBean" class="org.jboss.example.SimpleBean">
    <property name="list" preinstantiate="false">
        <list elementClass="java.lang.String">
            <value>string1</value>
            <value>string2</value>
        </list>
    </property>
</bean> 

Note

If you want to define a clazz /class attribute for an array then you must use the following syntax:

[L <fully-qualified class name> ;

e.g. an array of strings - [Ljava.lang.String;

or an array of integers - [Ljava.lang.Integer;