The dependency injection builder

Following object-oriented design principles typically lead to applications consisting of many classes that model entities of the real world that belong to the problem domain of the application. During application runtime instances of these classes are created. Each object is responsible for a specific task. To implement the application's functionality the objects have to interact with each other in complex ways. Therefore they need references to their collaborators. In total this forms a complex network of objects in the application's memory.

In its initialization phase an application has to create the network of its objects somehow. This is not trivial, and it is worth thinking about how this task can be achieved best.

One possibility would be to let the objects create their helper objects themselves. Then the application would only need to instantiate the root objects in the network. All other objects would then be created automatically. This solution works, but it is problematic. One point is that the whole construction process is very inflexible. Objects and the references between them are hard-coded in the application's initialization logic. This makes it very hard to change parts of the object network. Also testing of single classes is hard because if a class creates all its helper objects directly, it is hardly possible to inject stub or mock objects for them. Another point is that care must be taken if the network contains shared references. In this case special logic must be added to ensure that the corresponding target objects are not instantiated multiple times.

Another solution could be a lookup service: Objects that need references to other objects do not create these objects directly, but are passed a service object from which they can request references to other objects. The implementation of the lookup service is then responsible for the creation of the requested objects. An example for such a lookup service is JNDI. The lookup service solution improves the situation and solves some of the problems mentioned above. For instance, the lookup service can be mocked itself, and thus it is possible to pass mock or stub objects to classes that are to be tested. However, there is still a lot of boiler plate code needed to construct the whole network of objects. Every class that has references needs to interact with the lookup service.

For some time another approach has become very popular: dependency injection. In a nutshell, dependency injection means that classes are not responsible at all to create objects they depend on or obtain the corresponding references somehow. Rather, they only provide means that allow these references to be set, e.g. through constructor parameters or through corresponding set methods. Further, there is some kind of description that defines which classes need which other helper objects. Another component, the dependency injection container, reads this description and creates the complete object graph based on this information. This involves creating all object instances and initializing the references to the dependent objects. Dependency injection greatly simplifies the construction of complex object networks. Neither the classes involved nor the application's initialization code has to take care about object creation. Instead all the logic required for constructing the graph of objects is implemented in the dependency injection container in a generic way. Classes that are part of the graph only have to adhere to simple conventions so that the needed references can be passed in (e.g. they can be Java beans and define corresponding set methods). This makes testing these classes in isolation very easy because a test class can use the same conventions for passing in mock objects.

Because dependency injection has many advantages there are many implementations of this concept. The most popular ones are certainly Spring and Google Guice. The JGUIraffe library also implements a lean dependency injection framework. You may ask why another dependency injection framework is needed if there are already well-known and proven implementations.

Well, one point is that dependency injection is such a nice concept that it has been adopted by many other frameworks in different areas. For instance, some web application frameworks use it to connect the components implementing business logic together. Also the Swing application framework uses a kind of dependency injection to pass data defined in resource property files to components of the UI. So integrating the concept of dependency injection into frameworks actually makes sense.

Another reason for JGUIraffe's support for dependency injection is that it really plays nicely together with the builder approach outlined in the last section. JGUIraffe uses XML builder scripts to define the graphical user interface of an application. These scripts can also contain definitions for objects to be created, e.g. controller classes or validators. The newly created objects can directly be connected with elements of the UI. For instance, a dialog is typically associated with a controller object. The controller can be defined in the same script as the dialog itself, and it can be passed references to UI components it needs to interact with. After the builder script has been processed all objects have been created and are correctly connected with all their dependent objects - no further initialization is required for the application. We will see how this works in practice later in this section.

Fundamental concepts and interfaces

Before we come to concrete examples of using dependency injection in JGUIraffe applications some fundamental concepts have to be introduced. The basic idea is that objects to be created are defined in XML builder scripts (processed by Commons Jelly as regular builder scripts). These objects are also referred to as "beans" because they typically follow well-known Java beans conventions. After a builder script with bean definitions have been processed special context objects are available through which the beans can be queried so that instances can be obtained. We give an introduction of the most important interfaces involved in this process.

When working with the dependency injection framework it is all about bean definitions: a builder script is processed, and the beans defined there are stored in internal data structures from where they can be accessed by the application. An important data structure for storing bean defininitions is a BeanStore. A BeanStore groups a number of bean definitions together and provides a very basic API to access them. An application rarely uses a BeanStore directly because there are other classes implementing a more convenient API on top of it. However, in builder scripts tags can be used for creating bean stores and for assigning bean definitions to them. This can make sense if there is a logic grouping for the beans used by an application and the beans should really be separated. (If it is more convenient for an application to store all their beans in a single place, it need not worry much about bean stores). An important point to know about bean stores is that they form a hierarchical structure: a BeanStore can have a parent bean store. This also is related to the visibility of beans. A child bean store can access bean definitions in its parent, but not vice versa. For typical use cases this hierarchy is convenient. When an application starts up a root bean store is created and populated with bean definitions. If later another window is to be opened - say a dialog form -, the root bean store becomes the parent of the bean store created when processing the builder script for the new window. Thus it is possible to access the beans defined in the root store from the newly created window.

As said before, a BeanStore is mainly used internally by the framework to organize bean definitions. The interface used by clients is BeanContext. A BeanContext provides a bunch of methods for accessing beans. Internally, it is associated with a BeanStore. When it is queried for a bean it searches the BeanStore and its parents if necessary until a corresponding bean definition is found. Then the bean is created if required and returned. If a bean is to be newly created, all dependencies for this bean have to be resolved. This can cause the creation of many other beans, depending on the dependencies defined for this bean. If the bean can be reused, it is cached so that it can be directly returned when it is requested the next time.

The following example shows how a BeanContext object is used for querying a bean with a given name:

BeanContext beanCtx = ...  // obtain the context
MyBeanClass bean = (MyBeanClass) beanCtx.getBean("myBeanName");
    

Each bean definition has a unique name, by which it can be accessed from a BeanContext. Alternatively, the bean can be specified by its class - provided that there is only a single bean definition using this class. In this case the example looks as follows:

BeanContext beanCtx = ...  // obtain the context
MyBeanClass bean = beanCtx.getBean(MyBeanClass.class);
    

Note that the type cast is no more necessary because the method uses Java's generics. Note further that the class passed to getBean() does not have to match exactly the class in the bean definition; rather, it can be a super type (including an interface). This conforms to good practice: the application can program against an interface which is used in the getBean() call; in the bean definition the concrete implementation is provided.

In addition to the getBean() methods the BeanContext interface defines methods for listing the available bean definitions and for checking whether a specific bean definition exists in the context. Most methods come in two variants: One variant takes a BeanStore object as argument, and the other does not. The method without the BeanStore argument operates on the default bean store set for this BeanContext. The other variant accesses the specified BeanStore. (Because a BeanContext mainly implements additional logic on top of a BeanStore it can operate on an arbitrary BeanStore instance.)

Now where we have discussed how a BeanContext object can be used to query beans, you certainly want to know how a BeanContext can be created and initialized. Setting up a BeanContext requires a builder which can process a bean definition file. There are two options:

  • A specific bean builder can be used that is only able to process bean definition files. This is slightly more efficient than the other option, but the API is a bit more involved, and you are actually limited to a sub set of tags related to the dependency injection framework.
  • Alternatively the regular builder described in the section Introducing builders is also capable to process bean definitions. This is convenient because this way beans can be defined together with the UI of the application.
We will shortly provide more details about these two options. Because using the standard builder is more powerful and convenient than invoking the specific bean builder the first option is rarely used. Nevertheless it makes sense to discuss bean builders, too, because the interfaces used here are also of importance in the second approach.

In order to invoke a bean builder, the following steps have to be performed:

  1. A BeanBuilderFactory has to be obtained from the central Application object.
  2. Using the factory a new BeanBuilder instance can be created.
  3. The BeanBuilder class defines a build() method which processes a Jelly script with bean definitions. It returns a BeanBuilderResult object with the results of the builder operation.
  4. The BeanBuilderResult object allows access to all BeanStore objects created while the builder script was processed. From the information stored in this object a BeanContext can be created.
In source code these steps look as follow:
BeanBuilderFactory factory = application.getBeanBuilderFactory();

try
{
    BeanBuilder builder = factory.getBeanBuilder();
    Locator beanDefs = ... // locator to the script to be processed
    BeanBuilderResult result = builder.build(beanDefs, null, null);
    BeanContext beanContext = new DefaultBeanContext(result.getBeanStore(null));
}
catch(BuilderException bex)
{
    // exception handling
}
    

Obtaining the BeanBuilderFactory and the BeanBuilder from the factory should be clear. Then a Locator object is created that points to the bean definition file to be processed. This object is passed to the builder's build() method as first argument. For the other arguments null is passed, which means that default values are used. The second argument is of type MutableBeanStore. If here an object is provided, all bean definitions parsed are added to this store. Otherwise, a new BeanStore is created. The third parameter of the build() method is a ClassLoaderProvider object. We come back to this class later in the section with advanced topics. For now it is sufficient to know that null can be passed for a default provider.

build() returns a BeanBuilderResult object. This object can be queried for all BeanStore objects created during the builder operation. As mentioned earlier, bean definitions can be organized in multiple bean stores. Each bean store has a unique name. The bean store with the name null is the root bean store, i.e. the top element in the hierarchical structure of bean stores. The example script obtains this root bean store and passes it to a newly created DefaultBeanContext object. DefaultBeanContext is the default implementation of the BeanContext interface. Note that both the BeanBuilderFactory and the BeanBuilder can throw a BuilderException if something goes wrong. So this exception has to be handled.

The BeanBuilder API is pretty basic and thus it is harder to use. The other builders provided by the JGUIraffe library which are responsible for the creation of UI elements are implemented on top of the bean builder. They hide much of the complexity of the bean builder API. The key here is the BuilderData object that has to be passed to the builder: After the builder operation completes it contains some fully initialized objects allowing access to bean stores and bean definitions created while processing the builder script. This includes

  • the BeanBuilderResult object which provides access to all BeanStore objects, and
  • a BeanContext object associated with the root bean store.
So the code for calling the builder and obtaining the BeanContext becomes much simpler:
Builder builder = application.getApplicationContext().newBuilder();
ApplicationBuilderData builderData = application
        .getApplicationContext().initBuilderData();
try
{
    Locator locator = ClassPathLocator.getInstance("mybeans.jelly");
    builder.build(locator, builderData);
    BeanContext beanContext = builderData.getBuilderContext();
}
catch(BuilderException bex)
{
    // exception handling
}
    

This is pretty similar to the example code introduced in the section Invoking a builder. The BuilderContext can be obtained directly from the BuilderData object. Again, a BuilderException has to be handled. In the next section we deal with Jelly scripts that contain bean definitions and discuss the different ways of defining beans.

Scripts with bean definitions

Scripts that are used to define beans must be complient with Commons Jelly which is used to interpret them. Therefore they have to be valid XML documents.

Structure of bean definition scripts

The following code fragment shows the fundamental structure of such a builder script:

<?xml version="1.0" encoding="ISO-8859-1"?>
<j:jelly xmlns:j="jelly:core" xmlns:di="diBuilder">

  <!-- Beans to be stored in the root store.-->
  <di:bean name="rootBean" beanClass="net.sf.jguiraffe.di.ReflectionTestClass"/>
  ...
  <!-- A bean store definition with nested beans.-->
  <di:store name="beanStore1">
    <di:bean name="store1Bean" beanClass="..."/>
    ...
  </di:store>
  ...
  <!-- Another bean store definition.-->
  <di:store name="beanStore2" parentName="beanStore1">
  ...
  </di:store>
</j:jelly>
    

The document starts with a typical XML declaration that also defines the encoding (the encoding is optional). Then the root element <j:jelly>with the namespace declarations follows. Two namespace prefixes are defined:

  • j for core Jelly tags. This means that all standard tags available in Jelly can be used in the script.
  • di for tags of the JGUIraffe dependency injection tag library (di stands for dependency injection). So all tags starting with the prefix di are expected to be part of the dependency injection tag library.
When using other builders, e.g. for creating form elements or windows, further namespace declarations can be added.

Below the root element beans can be defined using <di:bean> tags. If not specified otherwise, these bean definitions are added to the root BeanStore. The root bean store is either passed to the builder's build() method or it is created automatically.

With the <di:store> tag additional bean stores can be created. The beans that should be stored in these stores can be defined by nested <di:bean> tags. Alternatively the <di:bean> tag supports the store attribute that can be used to specify the name of the target bean store. Because bean stores can form a hierarchical structure the <di:store> tag supports a parentName attribute; here the name of the parent store can be provided. If this attribute is undefined, the new bean store becomes a child of the root bean store.

Simple bean definitions

The example script in the previous section already showed the declaration of a simple bean:

<di:bean name="rootBean" beanClass="net.sf.jguiraffe.di.ReflectionTestClass"/>
    

A bean must have a unique name. This is the name that is also passed to a BeanContext when querying the bean. In the most simple form the class of the bean is specified using its fully qualified name. If this form of a bean declaration is used, the class must have a default constructor. This constructor is invoked to create the bean instance. By the way, this example and most of the following ones use the ReflectionTestClass class to demonstrate the various ways of defining beans. The source code of this class can be found below:

package net.sf.jguiraffe.di;

public class ReflectionTestClass
{
    /** A test member field. */
    private String stringProp;

    /** Another test member field. */
    private int intProp;

    /** A property storing arbitrary data.*/
    private Object data;

    /**
     * Creates a new instance of <code>ReflectionTestClass</code>. Default ctor.
     */
    public ReflectionTestClass()
    {
        this(null, 0);
    }

    /**
     * Creates a new instance of <code>ReflectionTestClass</code> and initializes
     * the properties.
     *
     * @param s the string property
     * @param i the int property
     */
    public ReflectionTestClass(String s, int i)
    {
        this(i);
        stringProp = s;
    }

    /**
     * Creates a new instance of <code>TestClass</code> and initializes
     * the string property.
     *
     * @param s the string property
     */
    public ReflectionTestClass(String s)
    {
        this(s, 0);
    }

    public String getStringProp()
    {
        return stringProp;
    }

    public void setStringProp(String stringProp)
    {
        this.stringProp = stringProp;
    }

    public int getIntProp()
    {
        return intProp;
    }

    public void setIntProp(int intProp)
    {
        this.intProp = intProp;
    }

    public Object getData()
    {
        return data;
    }

    public void setData(Object data)
    {
        this.data = data;
    }

    /**
     * Initializes the properties of this instance.
     *
     * @param s the string property
     * @param i the int property
     * @return the old value of the string property
     */
    public String initialize(String s, int i)
    {
        String result = getStringProp();
        setStringProp(s);
        setIntProp(i);
        return result;
    }

    /**
     * A static factory method for testing static method invocations.
     *
     * @param s the string property
     * @param i the int property
     * @return the newly created instance
     */
    public static ReflectionTestClass getInstance(String s, int i)
    {
        return new ReflectionTestClass(s, i);
    }
}
    

Well, this class does not do anything meaningful, but there are many ways to construct new instances, including various constructors and a static factory method. These will be used by the examples following in this section.

Singleton and non-singleton beans

A singleton is a class from which only a single instance exists during runtime of an application. The singleton pattern is often used to hold central information that must be accessible from any parts of an application. If implemented by hand, typically static instance fields and methods are used to ensure the singleton property.

Because the dependency injection framework controls when an instance of a bean is created it is easy to make specific beans a singleton. The framework only has to cache the instance after its creation and return it again if it is queried later on. Actually this is the default behavior for bean definitions. Whether a bean is a singleton or not is controlled by the boolean singleton attribute of the <bean> tag whose default value is true:

<!-- A singleton bean -->
<di:bean name="singletonBean" beanClass="net.sf.jguiraffe.di.ReflectionTestClass"/>

<!-- Not a singleton bean -->
<di:bean name="nonSingletonBean" singleton="false"
  beanClass="net.sf.jguiraffe.di.ReflectionTestClass"/>
    

In this example the first bean is a singleton while the other is not. If this script is processed by a builder, the following assertians are true:

ReflectionTestClass bean1 =
  (ReflectionTestClass) beanContext.getBean("singletonBean");
assert bean1 == beanContext.getBean("singletonBean");

ReflectionTestClass bean2 =
  (ReflectionTestClass) beanContext.getBean("nonSingletonBean");
assert bean2 != beanContext.getBean("nonSingletonBean");
    

So every time a non-singleton bean definition is accessed, a new instance of this bean is created.

Constant values

The <di:bean> tag allows defining beans that are assigned constant values. These beans are created immediately when the script is processed by the builder. They are always singletons. This is typically used for primitive values. The following example fragment shows some constant definitions:

<di:bean name="intConst" value="42" valueClass="java.lang.Integer"/>
<di:bean name="strConst" value="Test"/>
    

Here a java.lang.Integer and a java.lang.String bean are defined. The value attribute of the <di:bean> tag is responsible for assigning a value. With the valueClass attribute the data type of the value can be specified. It is String per default; so in case of the integer value it must be provided in order to perform the correct type conversion.

Invoking a constructor

So far beans were created only by calling their default constructor. Of course, it is possible to invoke other constructors as well. This is done using a nested <di:constructor> tag. In the next example the constructor of ReflectionTestClass is invoked that expects the values of the string and the integer property:

<di:bean name="constructor"
  beanClassName="net.sf.jguiraffe.di.ReflectionTestClass">
  <di:constructor>
    <di:param parameterClass="java.lang.String" value="test string"/>
    <di:param value="42"/>
  </di:constructor>
</di:bean>
    

The <di:constructor> tag can have an arbitrary number of nested <di:param> tags representing the parameters of the constructor to be invoked. The value attribute of the <di:param> tag specifies the value to be passed. With the optional parameterClass attribute the data type of the parameter can be specified. This is normally not necessary because the type can be inferred by the parameters of the constructor. However, if there are multiple constructors with similar parameter types it may be required to use the attribute to avoid ambiguities. If values need to be converted to other types, the valueClass attribute can be provided. More information about parameters with different data types can be found in the sub section Parameter matching and data type conversions later in this chapter.

Invoking a static factory method

What if the bean to be created does not define a constructor, but it uses a static factory method? The ReflectionTestClass class used in the tests has a static getInstance() method that can also be invoked to create new instances. In the builder script the <di:factory> tag in collaboration with the <di:methodInvocation> tag is used to achieve this:

<di:bean name="staticFactory"
  beanClass="net.sf.jguiraffe.di.ReflectionTestClass">
  <di:factory>
    <di:methodInvocation method="getInstance"
      targetClass="net.sf.jguiraffe.di.ReflectionTestClass">
      <di:param value="test String"/>
      <di:param value="42"/>
    </di:methodInvocation>
  </di:factory>
</di:bean>
    

With the <di:methodInvocation> tag (which is implemented by the MethodInvocationTag class) the method to be invoked is specified. Parameters are provided as nested <di:param> tags. In this case we invoke a static method on the ReflectionTestClass class - as defined by the targetClass attribute. The <di:factory> tag also allows invoking methods on other beans. This way non-static factory methods can be used, too. More information can be found in the documentation of the FactoryTag class.

Setting properties

If a bean class fully adheres to the Java Beans specification, it has a standard constructor and get and set methods for its properties. To create and initialize such a bean first the standard constructor must be called, then the properties can be set. We have already seen how to invoke the standard constructor of a class. With nested <di:setProperty> tags properties of the newly created bean can be set.

<di:bean name="propertiesBean"
  beanClass="net.sf.jguiraffe.di.ReflectionTestClass">
  <di:setProperty property="intProp" value="42"/>
  <di:setProperty property="stringProp" value="This is a test."/>
</di:bean>
    

The attributes of the <di:setProperty> tag are very similar to the <di:param> tag. A full description of all supported features can be found in the documentation of the SetPropertyTag class. The property names passed to the property attribute conform to the Java Beans specification: A property named foo requires the existence of a public method named setFoo() in the corresponding class.

Dependencies to other beans

At the beginning of this chapter it was stated that the major advantage of the dependency injection approach is that dependencies to other objects are automatically provided when beans are created. So far we have not dealt with dependencies yet.

References to other beans can be specified in both constructor arguments or when setting properties. Actually the <di:setProperty> and the <di:param> tags work very similar in the way their data can be specified. The following options are supported:

  • Constant values can be specified using the value attribute (plus an optional valueClass or valueClassName attribute). We have seen this before.
  • With the refName attribute the reference to another bean can be specified. Here the name of the bean has to be provided. A bean with this name must exist in the same bean store or in one of its parents.
  • Alternatively to the name of the dependent bean its class can be specified to the refClass attribute. This is analogous to the getBean() methods of the BeanContext class which allow requesting a bean by name or by its class.
  • It is also possible to place a nested <di:bean> tag in the body of a <di:setProperty> or <di:param> tag. Then this bean becomes the data of the nesting tag.

We provide some examples for these features. In the first example we use the refName attribute to refer to other beans in the script. In the subsection Constant values a string and an integer constant have been defined. Now we reference these beans:

<di:bean name="constantDependencies"
  beanClass="net.sf.jguiraffe.di.ReflectionTestClass">
  <di:constructor>
    <di:param refName="strConst"/>
  </di:constructor>
  <di:setProperty property="intProp" refName="intConst"/>
</di:bean>
    

As can be seen, it is possible to mix the invocation of constructors with the setting of properties. Here we call the constructor that expects a string parameter and pass the constant string bean. Then we set the integer property and pass the constant integer bean.

In the next example an instance of ReflectionTestClass is defined, and its data property is assigned another instance which is defined in place (the data property is of type java.lang.Object, so it accepts properties of all types).

<di:bean name="inplaceBean" beanClass="net.sf.jguiraffe.di.ReflectionTestClass">
  <di:setProperty property="data">
    <di:bean beanClass="net.sf.jguiraffe.di.ReflectionTestClass">
      <di:constructor>
        <di:param refName="strConst"/>
        <di:param refName="intConst"/>
      </di:constructor>
    </di:bean>
  </di:setProperty>
</di:bean>
    

In this case the <di:setProperty> tag has no attribute defining any value to be set. Instead, the value is specified by the <di:bean> tag in the body of the tag. Here another ReflectionTestClass instance is defined and initialized. Note that this nested <di:bean> tag does not have a name attribute; it is an anonymous bean declaration that is only used in this specific place. What is demonstrated here for the <di:setProperty> tag works exactly the same for the <di:param> tag. Thus references to other beans can be passed to constructors or other methods as well.

A related question is how to specify a null value. For instance, ReflectionTestClass has a constructor that expects a string and an integer parameter. How can this constructor be invoked passing in null for the string? This can be achieved using the <di:null> tag:

<di:bean name="nullParam" beanClass="net.sf.jguiraffe.di.ReflectionTestClass">
  <di:constructor>
    <di:param><di:null/></di:param>
    <di:param value="42"/>
  </di:constructor>
</di:bean>
    

Collections

Some beans have properties or constructor arguments that require a collection. The dependency injection tag library provides several tags for creating various types of collections. Here is an example of how a list can be created and passed as value to a property:

<di:bean name="list" beanClassName="net.sf.jguiraffe.di.ReflectionTestClass">
  <di:setProperty property="data">
    <di:list elementClassName="java.lang.Integer">
      <di:element value="1"/>
      <di:element value="2"/>
      <di:element value="1000" valueClassName="java.lang.Long"/>
    </di:list>
  </di:setProperty>
</di:bean>
    

The <di:list> tag (implemented by the ListTag class) creates the list. With the optional attributes elementClass or elementClassName the class of the single list elements can be specified. <di:element> tags in the body of the <di:list> tag define the list elements. They inherit the class of the elements, so that the string values in this example are automatically converted to integer values. The last <di:element> tag overrides this class using the valueClassName attribute - it produces a Long value.

The <di:element> tag provides multiple ways to define the element to be added to the list. Full documentation is available at the ElementTag class which implements this tag. Actually the tag supports the same options as the <di:setProperty> or the <di:param> tags. For instance, list elements can be defined as references to other beans, or by nested anonymous bean definitions. The following example shows some of these possibilities:

<di:bean name="listDependency" beanClassName="net.sf.jguiraffe.di.ReflectionTestClass">
  <di:setProperty property="data">
    <di:list>
      <di:element/>
      <di:element refName="intConst"/>
      <di:element>
        <di:bean beanClass="net.sf.jguiraffe.di.ReflectionTestClass"/>
      </di:element>
    </di:list>
  </di:setProperty>
</di:bean>
    

Here the first <di:element> tag is empty. It produces a null element that is added to the list. The second tag refers to the bean with the name intConst. The third one evaluates the nested bean declaration and creates another instance of the ReflectionTestClass class. If a java.util.Set is needed rather than a java.util.List, the declaration looks very similar: the <di:list> tag has to be replaced by the <di:set> tag:

<di:bean name="set" beanClassName="net.sf.jguiraffe.di.ReflectionTestClass">
  <di:setProperty property="data">
    <di:set elementClassName="java.lang.Integer">
      <di:element value="1"/>
      <di:element value="2"/>
      <di:element value="1000" valueClassName="java.lang.Long"/>
    </di:set>
  </di:setProperty>
</di:bean>
    

This example works analoguously to the first example for lists, just that a java.util.HashSet is created and populated by the <di:element> tags. The <di:set> tag supports an additional ordered attribute of type boolean. If set to true, the order of the elements added to the set is kept - in this case the tag creates a java.util.LinkedHashSet object rather than a java.util.HashSet instance:

<di:bean name="set" beanClassName="net.sf.jguiraffe.di.ReflectionTestClass">
  <di:setProperty property="data">
    <di:set elementClassName="java.lang.Integer" ordered="true">
      <di:element value="1"/>
      <di:element value="2"/>
      <di:element value="1000" valueClassName="java.lang.Long"/>
    </di:set>
  </di:setProperty>
</di:bean>
    

The definition of a map looks pretty similar. The <di:map> tag is used (implemented by the MapTag class) which supports optional attributes for specifying the class of the map's keys and values. Instead of the <di:element> tag the <di:entry> tag is used to define a key-value-pair to be added to the map:

<di:bean name="map" beanClassName="net.sf.jguiraffe.di.ReflectionTestClass">
  <di:setProperty property="data">
    <di:map keyClass="java.lang.String" valueClass="java.lang.Integer">
      <di:entry key="key1" value="1"/>
      <di:entry key="key2" value="2"/>
      <di:entry key="key3" value="1000" valueClass="java.lang.Long"/>
    </di:map>
  </di:setProperty>
 </di:bean>
    

This example creates a map with strings as keys and numbers as values. The default value class is java.lang.Integer, the last <di:entry> tag however produces a java.lang.Long object. <di:entry> can be used analogously to <di:element> to define complex values, e.g. by referencing other beans or by defining beans in the tag's body. Refer to the documentation for the EntryTag class for a full list of all supported attributes. But what if the key of the entry is a complex object? In this case the <di:entryKey> tag can be used. It also supports all options of defining complex objects which then become the key of the entry. The following example demonstrates this. It creates a map with an entry whose key is a list and whose value is a set:

<di:bean name="mapcomplex" beanClassName="net.sf.jguiraffe.di.ReflectionTestClass">
  <di:setProperty property="data">
    <di:map ordered="true">
      <di:entry>
        <di:entryKey>
          <di:list elementClassName="java.lang.Integer">
            <di:element value="1"/>
            <di:element value="2"/>
            <di:element value="1000" valueClassName="java.lang.Long"/>
          </di:list>
        </di:entryKey>
        <di:set elementClassName="java.lang.Integer" ordered="true">
          <di:element value="1"/>
          <di:element value="2"/>
          <di:element value="1000" valueClassName="java.lang.Long"/>
        </di:set>
      </di:entry>
    </di:map>
  </di:setProperty>
</di:bean>
    

As is true for the <di:set> tag, <di:map> supports the ordered attribute. If set to true, a java.util.LinkedHashMap is created which keeps track of the order in which entries have been added.

Finally, there is a special tag for defining java.util.Properties objects. Properties objects are similar to maps, but both keys and values are strings. The definition of a Properties object is almost identical to the definition of a map: only the <di:map> tag has to be replaced by the <di:properties> tag:

<di:bean name="properties" beanClassName="net.sf.jguiraffe.di.ReflectionTestClass">
  <di:setProperty property="data">
    <di:properties>
      <di:entry key="db.usr" value="scott"/>
      <di:entry key="db.pwd" value="tiger"/>
      <di:entry key="db.src" value="defaultDS"/>
    </di:properties>
  </di:setProperty>
</di:bean>
    

Complex string values

When string values have to be passed to constructors or properties, so far we have used the value attribute of the <param> or <setProperty> tag for this purpose. This works fine for simple strings, but fails if the strings are longer and should span multiple lines. In this case the <value> tag (implemented by the ValueTag class) can be used. <value> tag obtains the string value from its body which can become arbitrary complex. It is recommended to put the body in a CDATA section so that special characters can be used without quoting. The following example passes a string as constructor parameter that spans multiple lines:

<di:bean name="valueTest" beanClass="net.sf.jguiraffe.di.ReflectionTestClass">
  <di:constructor>
    <di:param>
      <di:value><![CDATA[Line 1
Line 2
Line 3]]></di:value>
      </di:param>
    </di:constructor>
  </di:bean>
    

Access to constants

It is sometimes necessary to reference a value that is defined as a constant (a public static final member field) in a class. For this purpose, the DI library offers the <const> tag (which is implemented by the ConstantValueTag class). Consider for instance the following class that defines such a constant:

package com.acme.data;

public class Constants
{
    public static final int ANSWER = 42;
}
    

In order to create an instance of the reflection test class passing in the ANSWER constant as value for the constructor's int parameter, the following fragment can be used:

<di:bean name="constantTest" beanClass="net.sf.jguiraffe.di.ReflectionTestClass">
  <di:constructor>
    <di:param value="The question">
    <di:param>
      <di:const targetClass="com.acme.data.Constants"
        field="ANSWER"/>
    </di:param>
  </di:constructor>
</di:bean>
    

The tag fetches the value of the referenced field from the given target class and passes it to an enclosing tag. Alternatively, the var attribute can be used which assigns the field value to a variable in the Jelly context.

There is another option to directly expose the values of constants as beans. For instance, a Java class may define a default instance as an INSTANCE property; or Scala objects are exposed to Java as a static field named MODULE$. This can be achieved by a combination of the already discussed <const> tag and the <contextBean> tag (implemented by the ContextBeanTag class). The latter obtains an object stored in the Jelly context and makes it available as a bean in the current bean context. The idea is that the <const> tag is invoked with its var attribute to store the value of the constant field in the Jelly context. From there it can be accessed and exposed by the <contextBean> tag. The following example shows how this looks like for a Scala object implementing a service:

<di:const var="playlistServiceVar"
  targetClassName="com.acme.audio.playlist.service.PlaylistService$"
  field="MODULE$"/>
<di:contextBean var="playlistServiceVar" name="playlistService"/>
    

Here the PlaylistService can now be accessed from the bean context under the name playlistService.

Complex initializations

We have now discussed the most frequently used methods of defining beans using the tags of the dependency injection library. With these tags it should be possible to realize most of the use cases related to the creation of objects. For complex scenarios, for which these tags are not sufficient, there are some so-called invocation tags that allow invoking arbitrary methods on objects. If these tags are used, temporary objects can be created and stored in a local context that is valid during the processing of the nesting <di:bean> tag. Other tags, like <di:setProperty> or <di:param> can access these temporary objects. We provide an example that creates and initializes a ReflectionTestClass instance in a complicated way:

<di:bean name="initializer" singleton="false"
  beanClass="net.sf.jguiraffe.di.ReflectionTestClass">
  <di:constructorInvocation targetClassName="java.lang.StringBuilder"
    result="buf"/>
  <di:methodInvocation method="append" source="buf">
    <di:param parameterClass="java.lang.String" refName="strConst"/>
  </di:methodInvocation>
  <di:methodInvocation method="append" source="buf">
    <di:param parameterClass="java.lang.String" refName="strConst"/>
  </di:methodInvocation>
  <di:methodInvocation method="toString" source="buf" result="s"/>
  <di:setProperty property="stringProp" var="s"/>

  <di:methodInvocation method="valueOf" targetClass="java.math.BigInteger"
    static="true" result="i1">
    <di:param refName="intConst"/>
  </di:methodInvocation>
  <di:constructorInvocation targetClass="java.math.BigInteger" result="i2">
    <di:param value="2"/>
  </di:constructorInvocation>
  <di:methodInvocation method="multiply" source="i1" result="product">
    <di:param var="i2"/>
  </di:methodInvocation>
  <di:methodInvocation method="intValue" source="product" result="i"/>
  <di:setProperty property="intProp" var="i"/>
</di:bean>
    

What happens here? A set of <di:constructorInvocation> and <di:methodInvocation> tags is used for creating and manipulating some temporary objects which are eventually passed to properties of the bean created by the whole fragment. Note the special attributes of these tags:

  • source defines the name of the temporary object on which a method is to be invoked.
  • result specifies the name under which the result of a method invocation is stored in the temporary context. With other words, this creates a kind of variable.
The example fragment uses the <di:constructorInvocation> tag to create a new instance of java.lang.StringBuilder and stores it as a temporary object under the name buf. Then, using the <di:methodInvocation> tag, the append() method is invoked twice on this object passing in the bean with the name strConst. After that the content of the StringBuilder is transformed into a string by calling the toString() method and stored under the name s.

The next series of invocations creates two instances of java.math.BigInteger, one by invoking the static valueOf() method and one by calling a constructor. Then the product of these objects is created by invoking the multiply() method and stored under the name product. Finally the product is transformed into an integer object by invoking the intValue() method on it. <di:setProperty> tags are used to pass the results of these operations to properties of the newly created bean.

Well, this is certainly complex stuff, and we do not encourage such a programming style. It is obvious that such scripts are hard to understand and maintain. However, if you are forced to deal with legacy code, you might have no other option than performing complex method invocations in builder scripts. The last example shows that you can do so using the dependency injection tag library. For a full documentation of the invocation tags refer to the classes ConstructorInvocationTag and MethodInvocationTag.

Builder classes

If a class supports a bunch of configuration options which should be set at construction time, you may end up with a large number of different constructors: each constructor expects a specific set of configuration options while the remaining ones are set to default values. This allows a client to concentrate on the options of interest ignoring any others.

In such a scenario, a builder approach (not to be confused with the JGUIraffe builder scripts!) can be beneficial. Rather than providing many constructors, the class in question provides a specific builder class. The builder is instantiated and populated with the required options. Often this can be done through a fluent API which simplifies the usage of the builder for clients. Eventuelly, the builder creates an instance of its associated class based on the properties set so far. Typically, the class only provides a private constructor so that the builder is the only possibility to create instances.

An example of a class which provides a builder is BasicThreadFactory from the Apache Commons Lang project. The builder allows setting options like a naming pattern, a priority, or the daemon flag for the threads to be created by the factory. The following code fragment shows how this looks like in practice:

 BasicThreadFactory factory = new BasicThreadFactory.Builder()
     .namingPattern("factory_thread-%d")
     .daemon(true)
     .build();
     

While builders can be used elegantly from Java code, they are problematic for dependency injection frameworks. First an object of a different class than the actual bean class has to be created, then methods have to be called on it, and finally the result of the build() method must be used as the resulting bean. With the features introduced in the previous section you know how objects can be created and manipulated within complex builder scripts. The only missing piece is that you somehow have to tell the framework to use the result of a method invocation as resulting bean. This can be achieved by using the resultVar attribute of the <di:bean> tag. It tells the tag that it does not have to create a bean on its own, but use an object from a local variable of the initializer script instead. Below is an example which corresponds to the Java code presented above:

<di:bean name="threadFactory" resultVar="factory"
  beanClass="java.util.concurrent.ThreadFactory">
  <di:constructorInvocation result="builder"
    targetClassName="org.apache.commons.lang3.concurrent.BasicThreadFactory$Builder"/>
  <di:methodInvocation method="namingPattern" source="builder">
    <di:param value="factory_thread-%d"/>
  </di:methodInvocation>
  <di:methodInvocation method="daemon" source="builder">
    <di:param value="true"/>
  </di:methodInvocation>
  <di:methodInvocation method="build" source="builder" result="factory">
  </di:methodInvocation>
</di:bean>
     

Here a new instance of the nested Builder class is created using a <di:constructorInvocation> tag and stored in a local variable named builder (using the result attribute). Then on this object multiple methods are invoked. The last method call is to the build() method, and its result is stored in the factory variable. Note that this name is also used in the resultVar attribute of the <di:bean> tag; this establishes the connection to the tag's managed bean. Note also that on the embedding <di:bean> tag the beanClass attribute is defined. Defining the class of the resulting bean at this place is not strictly necessary for the correct creation of the bean. However, it allows the tag to correctly answer queries about the class of its managed bean, even if the bean has not yet been created. If the attribute was ommitted, querying the BeanContext for a bean of this class would fail. Therefore, the bean class should always be specified if the resultVar attribute is used.

Factory beans

Another use case for complex initialization scripts are factory beans: In cases when the creation of an object requires complex logic, it makes sense to extract this logic in a specific factory class. In order to create an instance of the original class, a reference to the factory object has to be obtained, and a specific creation method has to be invoked on it.

The factory beans use case is similar to the problem with Builder classes, but while a builder instance was created and stored in a variable local to the initialization script, we now have to reference another bean declared in the builder script. For this purpose, the dependency injection tag library provides the InvocationTargetTag tag. The tag can appear in the body of a MethodInvocationTag and references the target bean of the method invocation. It supports the possible dependencies as described in the section Dependencies to other beans. Below is an example which invokes the method create() on a bean with the name factoryBean:

<di:bean name="factoryBeanInvocation" resultVar="result">
  <di:methodInvocation method="create" result="result">
    <di:param value="someParameterValue"/>
    <di:invocationTarget refName="factoryBean"/>
  </di:methodInvocation>
</di:bean>
     

The <di:bean> tag again has the resultVar attribute to point to the local variable in which the result of the method invocation is stored. As you can see, it is possible to pass parameters to the method of the factory bean in the usual way.

Advanced topics

With the tags introduced so far complex bean definitions can be realized. In this section we discuss some edge cases of dependency management and provide some information about enhanced functionality which can be useful in special use cases.

Cyclic dependencies

When a bean is defined using the tags of the dependency injection framework all its dependencies can be declared. When this bean is requested from a BeanContext the dependent beans are resolved and are also created. If these beans declare additional dependencies, this can lead to a chain of beans being created. Problems can occur if cyclic dependencies occur. In the most simple case the cycle consists only of two beans referencing each other as shown in the following picture:

Cyclic dependency

Here bean A has a dependency to bean B and vice versa. In more complex scenarios the cycle can span multiple beans, e.g. bean A depends on bean B which depends on bean C which again depends on bean A. Whether this causes a problem or not depends on the way the dependencies are passed. Consider the following bean declarations:

<!-- Cyclic dependencies! Does not work! -->
<di:bean name="beanA" beanClassName="net.sf.jguiraffe.test.BeanA">
  <di:constructor>
    <di:param refName="beanB"/>
  </di:constructor>
</di:bean>

<di:bean name="beanB" beanClassName="net.sf.jguiraffe.test.BeanB">
  <di:constructor>
    <di:param refName="beanA"/>
  </di:constructor>
</di:bean>
    

Here it is tried to pass the beans to each other using the constructors. In this scenario it is impossible to find a working order in which the beans can be created: for the creation of bean A bean B must be available and vice versa. Because of this the framework gives up and throws an exception.

To work around this problem a valid order has to be found in which the beans can be created thus breaking the cycle. This can be achieved if one of the beans is not passed as constructor argument, but as a property as in the following example:

<!-- Cyclic dependencies! This works. -->
<di:bean name="beanA" beanClassName="net.sf.jguiraffe.test.BeanA">
  <di:constructor>
    <di:param refName="beanB"/>
  </di:constructor>
</di:bean>

<di:bean name="beanB" beanClassName="net.sf.jguiraffe.test.BeanB">
  <di:setProperty property="breference" refName="beanA"/>
</di:bean>
    

The framework is able to separate the creation of beans from their initialization. In this case it detects that there is still a cyclic dependency between the beans A and B. For the creation of bean A bean B is required. But bean B can be created without any dependencies (through its default constructor). So the framework creates bean B first, but defers its initialization (the set property operation). Then bean A can be created; it is passed the (so far not completely initialized) reference to bean B. Finally, the initialization of bean B can be completed because now bean A is available.

So the framework is usually smart enough to find a working creation order of dependent beans if possible. However, in this case the beans must be aware that the references passed to them may be only partly initialized. Only after the whole graph of beans has been created initialization is complete. This also works if the cycle contains more than two dependent beans.

Dependencies between singleton and non-singleton beans

If singleton beans have dependencies to non-singleton beans or vice versa, it may not always be obvious when and how many instances of the beans invloved are created. This sub section discusses some scenarios. We start with some simple cases. First imagine a singleton bean that references a non-singleton bean (Note: in this diagram and the following ones singleton beans are marked with a small "S" icon):

Singleton bean references non-singleton

When the singleton bean A is accessed the first time, it is created and initialized. In this process also a new instance of the non-singleton bean B is created and passed to the new A instance. Because A is a singleton, the instance is then cached and directly returned if bean A is requested again. Thus the reference to bean B remains constant, and only a single instance of this bean is created (at least as bean A is concerned).

Next let us have a look at the opposite scenario: a non-singleton bean has a dependency to a singleton bean:

Non-singleton bean references singleton

Now each access to bean B creates a new instance. Because bean A is a singleton, only a single instance of this bean is created. So all the different instances of bean B have the same reference to bean A.

So far there was no big surprise. Things become more complicate when multiple bean declarations are involved. Have a look at the following figure:

Multiple dependencies

When bean A is created the dependent beans B and C must be created, too. Both are non-singletons. Bean C also has a dependency to bean B. So how many instances of bean B are created? The answer is: only one, i.e. bean A and bean C share the same reference to bean B. When a bean is requested from a BeanContext all steps necessary to create this bean and all of its dependencies run in a kind of transaction. During this transaction only one instance of non-singleton beans is created. So if a non-singleton bean is referenced by multiple beans that are involved in a transaction, all these beans are initialized with the same reference.

Bean creation listeners

The BeanContext interface defines methods for adding and removing an object of type BeanCreationListener. A BeanCreationListener is notified whenever a bean is created. Note that this does not mean for every request of a bean, but only if a new instance of this bean is actually created, the listener is triggered. For a singleton bean the listener is invoked only once; for non-singleton beans it is called each time an instance is requested.

When a bean is created the beanCreated() method of the listener is called. This method is passed a BeanCreationEvent object that contains information about the newly created bean. This includes of course the new instance of the bean, but also some internal helper objects involved in the bean creation process (refer to the Javadocs for more information).

So what is the purpose of a BeanCreationListener? Such listeners come in handy if a bean needs information which is not available at configuration time, but only at application runtime. In this case a BeanCreationListener can intercept the bean creation process and provide the additional information. At the time the listener is called the bean has already been fully initialized according to its configuration. The listener only has to add the missing initialization.

As a concrete example consider a bean that needs to call a service for which user credentials are required, e.g. a web service or a database connection. For security reasons you do not want to store these credentials in a configuration file. One solution is to ask the user for the credentials and then use a BeanCreationListener to pass this data to the service bean when it is created.

As was said before, a BeanCreationListener can be added manually to a BeanContext by calling the addBeanCreationListener() method. If a standard builder is used (rather than a BeanBuilder), listeners can also be added to the ApplicationBuilderData object obtained from the ApplicationContext before it is passed to the builder. This has the advantage that the listeners are immediately active; they are then also triggered for beans created during the builder operation.

Class loader issues

Many tags of the dependency injection tag library have attributes which expect classes or class names. For instance, the <di:bean> tag has the beanClass attribute for specifying the class of the bean to be created; the <di:param> tag supports setting the parameter class; tags that allow setting a value also offer a means to define the value class.

What was not explained so far is the fact that all these attributes come in multiple variants. The most basic variant ends of the name "Class", e.g. beanClass, valueClass, or targetClass. These attributes work internally by using standard means provided by Jelly to load the corresponding Class object. This is appropriate for many desktop applications, but may fail in certain environments with multiple class loaders involved, e.g. in an OSGi container.

Therefore affected tag handler classes provide an alternative way to define classes. In addition to the attributes ending on "Class", there are corresponding attributes with the suffixes "ClassName", and "ClassLoader", e.g. beanClassName and beanClassLoader. The "ClassName" attribute gets passed the fully-qualified name of the desired Java class. This looks exactly the same as for the "Class" attribute, but internally a different mechanism is used to resolve the class name: Instead of using a default class loader, the class loader to be used can be specified by the "ClassLoader" attribute. This works as follows:

When calling the builder a ClassLoaderProvider object can be specified. If the bean builder is used, the ClassLoaderProvider is passed as an argument to the build() method. Otherwise, it is obtained from the parent BeanContext, which is a property of the BuilderData object. The ClassLoaderProvider interface defines a method that returns a class loader for a given symbolic name. If the "ClassName" attribute is used, the tags check whether the "ClassLoader" attribute is specified, too. In this case, the class is not resolved using the default class loader, but the ClassLoaderProvider is asked for a class loader with the symbolic name provided by the "ClassLoader" attribute. So it is possible to define an arbitrary class loader for resolving a class name. The following example shows how this mechanism is used in practice to obtain the class of a bean to be created from a specific class loader:

<di:bean name="myBean" beanClassName="com.mypackage.MyBeanClass"
  beanClassLoader="specialClassLoader">
</di:bean>
    

In this example the class loader registered for the name specialClassLoader is used to load the class com.mypackage.MyBeanClass. For this to work the class loader with the name specialClassLoader must be known to the ClassLoaderProvider. The ClassLoaderProvider interface has a registerClassLoader() method which can be used to register class loaders under symbolic names. A good place to register application-specific class loaders is the initClassLoaderProvider() method of the central Application class. This method is automatically called during application startup. It is passed the default ClassLoaderProvider which is used by all builder operations (unless an application overrides this default).

If an application has very specific requirements for loading classes, it can implement its own ClassLoaderProvider. In this case it may make sense to extend the default implementation, DefaultClassLoaderProvider. All class loader providers should support a special class loader with the symbolic name CONTEXT: if this name is passed, the context class loader for the current thread should be returned. This reserved name can also be used in tags to select the context class loader for resolving a class:

<di:bean name="myBean" beanClassName="com.mypackage.MyBeanClass"
  beanClassLoader="CONTEXT">
</di:bean>
    

The ClassLoaderProvider interface also provides a means to set a default class loader name. The class loader registered with this name is always used if the "ClassLoader" attribute is missing. This can be useful if most of the classes should be loaded by a specific class loader. To enable this feature, the best way is again to override the initClassLoaderProvider() method of Application. Here the setDefaultClassLoaderName() method of the ClassLoaderProvider object has to be called. The method expects a string parameter representing the name of the class loader to be used as default class loader. A class loader with this name must have been registered unless it is the reserved name CONTEXT referring to the context class loader. For some applications it may be indeed a good strategy to set the context class loader as default class loader.

As a general recommendation, for applications that work with multiple class loaders it is a good approach to avoid the "Class" attributes and use the "ClassName" attributes instead. The ClassLoaderProvider should be configured so that the defaultClassLoaderName property is set to the name of the class loader which is used most frequently. Then the "ClassLoader" attributes can be omitted in most cases because the default class loader is selected automatically. For classes to be resolved by a different class loader "ClassLoader" attributes have to be specified accordingly.

Access to class path resources

Beans declared for an application sometimes need access to resources defined in the class path. As an example, think about a properties file shipped in the application's jar that should be read by one of the service beans defined in a builder script.

Under normal conditions, access to such a file located on the class path is not that complicated: A corresponding URL can be resolved using a class loader. However, as described in the previous sub section, class loader structures can become complicated in special environments. Therefore, the dependency builder library provides a specialized tag for resolving a resource on the class path. The idea is as follows:

The tag is passed the name of the resource file to be resolved and the name of a variable in the Jelly context which takes the result of this operation. Optionally, a class loader name can be specified. The tag then uses the specified class loader (or the default class loader if none was provided) to obtain a URL pointing to the desired resource file. If this succeeds, the URL is converted to a string and written in the target variable. This variable can then be referenced in a bean declaration, for instance as a property value or a constructor argument. It is also possible to store the results of multiple resolve operations in a single variable. This can be achieved by specifying a delimiter string. The tag then checks whether the target variable already has a non-empty string value. If this is the case, the delimiter value is added followed by the result of the current operation. Otherwise, the variable is created or overridden with the current result.

The tag offering the described functionality is named <di:resource> and implemented by the ResourceTag tag handler class. We will provide a little example showing its usage. This example assumes that there is a service bean that has to read multiple properties file from the class path. It expects a comma-separated string with the URLs to be loaded passed to the constructor. This class could roughly look as follows:

public class PropertiesService
{
    /** String URLs of the files to be loaded. */
    private final String[] fileURLs;

    public PropertiesService(String files)
    {
        fileURLs = files.split(",");
    }
    ...
}
    

In the builder script the files to be loaded are declared in form of multiple instances of the <di:resource> tag and collected to a single string variable. This variable is then referenced in the bean declaration of the properties service bean:

<!-- Properties files to be loaded. -->
<di:resource resource="standard.properties" var="propertyFiles"/>
<di:resource resource="production.properties" var="propertyFiles" delimiter=","/>
<di:resource resource="special.properties" var="propertyFiles" delimiter=","/>

<!-- Declaration of the properties service bean -->
<di:bean beanClassName="com.mypackage.PropertiesService">
  <di:constructor>
    <di:param value="${propertyFiles}"/>
  </di:constructor>
</di:bean>
    

Note how the delimiter attribute is used to specify that all resolved resource files (except for the first one) should be concatenated to the same target variable. In the bean declaration the variable is referenced using the ${varName} notation used within Jelly.

Releasing resources

After a successful builder operation the application can access the resulting BeanContext and query beans. This causes beans to be created and - if singleton beans are involved - cached by the context. Some beans may acquire resources when they are created. If they are no longer used, these resources should be released. For instance, a bean representing a database connection should close this connection if it is no more needed.

The BeanBuilder interface defines a release() method which can be called with a BeanBuilderResult object when beans produced by the corresponding builder operation can be freed. This ensures that all cached beans are released.

In order to actually release resources occupied by beans, a shutdown handler can be defined in the bean declaration. A shutdown handler is defined using the <di:shutdown> tag. In the body of this tag arbitrary method invocation tags can be placed that are executed on shutdown (i.e. when the BeanBuilderResult is released). The following code fragment shows an example:

<di:bean name="shutdownMeth" beanClass="net.sf.jguiraffe.di.ReflectionTestClass">
  <di:shutdown>
    <di:methodInvocation method="shutdown"/>
  </di:shutdown>
</di:bean>
    

Actually, the body of a <di:shutdown> tag can become pretty complex. All tags can be placed here that can also be used to initialize a bean. Refer to the section Complex initializations for more examples. This includes tags for setting properties. The next example defines a shutdown handler which resets some properties of the bean when it is invoked:

<di:bean name="shutdown" beanClass="net.sf.jguiraffe.di.ReflectionTestClass">
  <di:setProperty property="intProp" refName="intConst"/>
  <di:setProperty property="stringProp" refName="strConst"/>
  <di:shutdown>
    <di:setProperty property="intProp" value="0" valueClass="java.lang.Integer"/>
    <di:setProperty property="stringProp"><di:null/></di:setProperty>
  </di:shutdown>
</di:bean>
    

As was already stated under Complex initializations, this feature should not be overused. Invoking a single shutdown method is fine, but writing complex shutdown scripts makes it hard to understand what happens at shutdown. Note that shutdown handlers are only supported for singleton beans. This is because only singleton beans are under the control of the dependency injection framework. From non-singleton beans an arbitrary number of instances can be created, and the framework has no chance to know when these instances are no longer needed.

We have explained how the results of a builder operation can be released. But when should the builder's release() method be called? If the bean builder is used directly, the developer is always responsible to call the release() method at the correct point of time. The advanced UI builders in contrast offer a convenience mechanism:

If the builder script defines a window, the framework can automatically register a specialized window event listener at this window. This listener will call the release() method when the window is closed. This mechanism assumes that all beans and resources are connected to the window object - which is typically the case in JGUIraffe applications; a builder script typically defines a window and its controls plus the beans needed by these graphical elements. As soon as the window becomes unavailable, all associated resources can be released. Whether the framework should register this special window listener or not is determined by the isAutoRelease() property of the BuilderData object passed to the builder. It is set to true per default.

Parameter matching and data type conversions

Throughout this chapter there have been lots of examples of bean declarations using constructors, set property operations, or method calls for initializing data fields of the objects to be constructed. To recapitulate, here is a typical code fragment defining a bean by calling its constructor:

<di:bean name="constructor"
  beanClassName="net.sf.jguiraffe.di.ReflectionTestClass">
  <di:constructor>
    <di:param parameterClass="java.lang.String" value="test string"/>
    <di:param value="42"/>
  </di:constructor>
</di:bean>
    

This code snippet is pretty simple, but it raises some questions which have not yet been addressed:

  • The second constructor parameter is of type int. How does the framework know this?
  • What if there are multiple constructors with similar parameter lists? How is the correct one identified?

These questions are closely related as we will see soon. To answer them we have to explain the algorithm used by the dependency injection framework to determine the constructor to call (the same algorithm is also applied to method invocations, so everything we say about constructors can be transferred to method invocations as well).

When a bean declaration contains a constructor invocation the framework tries to be clever to find the desired constructor. It iterates over all constructors provided by the target class and searches for a unique match. This works well if all constructors have a different number of parameters or some constructors can be sorted out based on the passed in arguments (for instance, passing a null value for a primitive parameter is not allowed). If at the end of the iteration only a single candidate is found, everything is fine.

However, if there are multiple constructors with similar parameter lists, it might not be possible to find a unique match. For instance, if the following additional constructor was added to the ReflectionTestClass class:

public ReflectionTestClass(Object obj, int i)
{
    this(i);
    data = obj;
}
    

the arguments test string and 42 could be passed to both of them. Actually, in this case the framework is not able to process the bean declaration and throws an exception. There are two options to solve this problem:

  • The <di:param> tag provides the parameterClass attribute. It tells the framework that this parameter is of the specified type. In this example, we could add a parameterClass attribute to the first <di:param> tag and set it to java.lang.String. This is sufficient to uniquely identify the desired constructor because there is only one constructor with two arguments whose first argument is of type String.
  • Alternatively, there is also a valueClass attribute. This attribute instructs the framework to directly convert the specified value to the given type. This also influences the search for a matching constructor because if no unique match is found, the framework checks the types of the arguments; from these types it may be able to exclude some of the constructors.

If everything works fine, there is only a single matching constructor. From the parameter list of this constructor the framework can detect the types of the expected arguments and compare them with the types of the passed in parameters. Because bean declarations are written in XML all parameters are initially strings. Using the valueClass attribute a conversion can be explicitly requested, so that the corresponding parameter already has the desired data type. For all other parameters the framework tries an implicit conversion to the data type specified by the constructor parameter. So here is the magic which automatically transforms the string 42 to an integer.

As a side note: When should I use parameterClass and when valueClass? In most cases, parameterClass is the option of choice. The goal is to give the framework a hint, which constructor to select. This is best achieved by providing enough parameterClass attributes so that a single constructor can be identified. You do not have to specify the type for all parameters, you only have to provide sufficient information that one constructor can be uniquely identified. The valueClass attribute is useful in cases where the actual parameter should be of a different (but of course compatible) type than the declared parameter. An example could be that the parameter type is an interface or an abstract base class. Then, with the valueClass attribute a concrete implementation class can be specified.

As was already stated, constructors were used as an example only. The same rules apply for method invocations and property set operations. For instance, if there is a bean declaration like the following one:

<di:bean name="property"
  beanClassName="net.sf.jguiraffe.di.ReflectionTestClass">
  <di:setProperty property="intProp" value="42"/>
</di:bean>
    

the framework can detect the correct data type of the property and perform a type conversion as necessary. For method invocations the situation is often easier than for constructors because in most cases there is only a single method with a given name. Hence, there is no problem with finding the correct method to invoke. Only if there are overloaded methods, ambiguities might occur which have to be resolved by specifying parameterClass attributes as necessary.

So in a nutshell, the following rules apply for matching constructors, methods, or properties:

  • The framework tries to find a unique match based on the number and types of the passed in arguments.
  • If there are ambiguities, e.g. caused by constructors or overloaded methods with similar parameter types, the developer has to provide hints to the framework in form of parameterClass attributes to ensure that only a single match is found.
  • Before the operation is actually executed the parameters are checked for compatibility with the declared parameters and are converted if necessary.

This algorithm is usually clever enough to find the correct constructor or method to be invoked so that the developer does not have to care. Only if exceptions are thrown because no unique match can be found, parameterClass attributes have to be added to resolve ambiguities. In the next sub section we will see which data type conversions are supported.

Data type converters

In the previous sub section it was stated that data type conversions of constructor or method arguments or properties are automatically performed as necessary. Of course, data type conversion is a complicated topic, and the framework is not able to perform arbitrary conversions. In the following we explain the basics and limitations of the data type converter subsystem.

Behind the scenes the Commons BeanUtils library is used for type conversions. BeanUtils provides some utility classes dealing with conversion issues and a number of default converters that can handle standard Java data types like primitives or date and time. These default converters are active per default and are applied to the values specified in bean declarations. Therefore beans defining only properties of basic types should work out of the box.

The dependency injection framework adds a few extensions to the default converters provided by the BeanUtils library:

  • There is a generic converter that can deal with enum classes. If the property of a bean is of an enum type, you just have to write the name of the corresponding constant in the bean declaration. This is best explained using an example. Consider the following declaration of an enum class:
    public enum Mode
    {
        DEVELOPMENT, TEST, PRODUCTION, CRITICAL
    }
        
    Now our standard test class for reflection operations is given a property of this enum class:
    private Mode mode;
    
    public Mode getMode()
    {
        return mode;
    }
    
    public void setMode(Mode mode)
    {
        this.mode = mode;
    }
        
    A bean declaration setting this property simply looks as follows:
    <di:bean name="enumProperty"
      beanClassName="net.sf.jguiraffe.di.ReflectionTestClass">
      <di:setProperty property="mode" value="PRODUCTION"/>
    </di:bean>
        
  • For some UI-related helper classes or other framework classes provided by the JGUIraffe library special converters are available. We will mention them in later chapters when we come to these classes.

Data type converters in Commons BeanUtils must implement the org.apache.commons.beanutils.Converter interface. This interfaces defines only a single method:

Object convert(Class type, Object value);
    

convert() is passed the desired target class and the object to be converted. It can perform arbitrary work to convert the given object to an instance of the target class. If this is not possible, a ConversionException can be thrown. In most cases the passed in object will be a String because it stems from the XML bean declaration. So writing a custom data type converter is no rocket science. You may also have a look at examples in the JGUIraffe source code, for instance, there is the EnumConverter class.

Before a custom type converter can be used it has to be registered first. For this purpose the dependency injection framework provides a thin layer around the Commons BeanUtils API. There are two classes that have to be dealt with:

  • ConversionHelper provides functionality directly related to type conversions. It also manages the data type converters which are currently active. Therefore an instance of this class has to be used to register new converters. It defines the following registration methods:
    • void registerConverter(Converter converter, Class<?> targetClass) registers a converter for the specified target class only.
    • void registerBaseClassConverter(Converter converter, Class<?> targetClass) registers a converter for the given class and all of its subclasses. This is useful if a converter can handle whole class hierarchies as is true for the EnumConverter already mentioned.
    When working with base class converters the order in which they are registered is important: The converters are searched in their reversed registration order, and the first one that can deal with the current class is selected. So if there is a converter for the base class A and one for the class B, and B is derived from A, the converter for A must be registered first, otherwise the converter for A would also be used for B objects. The reversed order might be counter-intuitive at first, but it allows applications to override default converters that have already been added by the framework.
  • An instance of the InvocationHelper class is active during the builder operation. It provides functionality for invoking constructors or methods through reflection; for instance, it implements the method matching algorithm described in the previous sub section. It also manages a ConversionHelper object which is used for converting properties or parameters.

In order to add a custom type converter to a builder operation an instance of ConversionHelper has to be created, and the converter has to be registered there. Then an instance of InvocationHelper has to be created with the ConversionHelper object. The BeanBuilder interface defines an overloaded variant of the build() method which can be passed an InvocationHelper object. The builder then uses this object for method invocations and all data type conversions. So the custom converter that has been registered at the ConversionHelper object managed by the InvocationHelper becomes active (all standard converters are automatically registered when a new ConversionHelper instance is created, so they are active per default). The following code fragment shows all steps required to register an instance of the MyConverter class for the class MyData:

// Prepare and register the converter
MyConverter converter = new MyConverter();
ConversionHelper convHelper = new ConversionHelper();
convHelper.registerConverter(converter, MyData.class);

// Create an InvocationHelper with the ConversionHelper
InvocationHelper invHelper = new InvocationHelper(convHelper);

// Call the builder
BeanBuilderFactory factory = application.getBeanBuilderFactory();
try
{
    BeanBuilder builder = factory.getBeanBuilder();
    Locator beanDefs = ... // locator to the script to be processed
    BeanBuilderResult result = builder.build(beanDefs, null, null, invHelper);
    BeanContext beanContext = new DefaultBeanContext(result.getBeanStore(null));
}
catch(BuilderException bex)
{
    // exception handling
}
    

Note that the InvocationHelper object is passed as last argument to the build() method of the builder. This approach works, but it is a bit inconvenient. The developer has to create multiple objects and perform the registration manually. In a later chapter we will see how custom data type converters can be declared in a builder script. They are then registered automatically.

Application standard beans

JGUIraffe internally makes use of its own concepts and also employs the dependency injection framework to configure some of its central services. There is a bean definition file named defaultbeans.jelly which is shipped with the framework. Each JGUIraffe application reads this file at startup.

defaultbeans.jelly defines a number of important beans that are used by JGUIraffe applications. Naming convention is that these beans start with the reserved prefix jguiraffe.. We give a short overview over the content of this file in the following. Note that some of the classes involved are discussed in later chapters, so there may be some forward references.

Bean name/group Description
jguiraffe.resourceLoader This is the resource loader, i.e. the object which actually accesses resources. Refer to the chapter Resources for more details.
jguiraffe.resourceManager The bean representing the resource manager. The resource manager provides access to localized texts. The bean is configured with the resource loader bean already mentioned.
jguiraffe.messageOutput A bean implementing the MessageOutput interface. It is used to produce message boxes in a way independent on a specific UI toolkit.
Validation beans A group of standard beans is related to the validation of input fields in forms. They are referenced and used by form controllers to implement functionality related to validation and to give the user feedback about validation results.
jguiraffe.validationMessageHandler
The handler for validation messages. This object controls the warning or error messages produced by validators. Refer to the chapter Transformers and Validators for more details.
jguiraffe.validationMessageFormat
This is the formatter for validation error messages. It is used by form controllers to generate a message for all invalid input fields in the form.
jguiraffe.formValidationTrigger
This bean controls when input validation is performed, e.g. when the user leaves an input field or at every keyboard event.
jguiraffe.fieldMarker
This bean is responsible for highlighting input fields which contain invalid data. The default implementation declared in defaultbeans.jelly changes the color of input fields to indicate the validation status. The colors used for this purpose are also declared as beans in the file. Their names start with the prefix jguiraffe.fieldMarker. followed by a term describing the status this color is associated with, e.g. jguiraffe.fieldMarker.invalidBg for the background color of an invalid field or jguiraffe.fieldMarker.notVisitedInvalidFg for the foreground color of a field with invalid data which has not yet been visited.
jguiraffe.classLoaderProvider Defines the class loader provider bean. Refer to the sub section Class loader issues for more details.
jguiraffe.bindingStrategy This bean defines the binding strategy used by forms to store their data in their model. Per default a strategy is defined which uses plain old Java beans as model objects.
jguiraffe.guiSynchronizer Here a bean is declared which controls access to UI elements. Most UI toolkits allow access to graphical elements only in a special thread, the event dispatch thread. The GUI synchronizer is an abstraction over this concept. It must be compatible with the UI toolkit used by the application. The implementation declared in the defaultbeans.jelly file is compatible with Swing.
jguiraffe.commandQueue Defines the concrete implementation of the command queue used by the application. Refer to the chapter Commands for more information.
jguiraffe.applicationContext The bean implementing the ApplicationContext interface. This declaration is a bit more complex because it contains a bunch of references to helper objects associated with the context.
Builder beans The builder for generating UIs, which is discussed in the chapter Building user interfaces and the following ones, is completely specified using standard beans. Each time a reference to the builder is requested, the main builder bean is obtained from the current BeanContext (and because this is not a singleton bean, a new instance is created). Multiple helper beans are involved:
jguiraffe.componentManager
This bean is responsible for the actual creation of UI elements. It must be compatible with the UI toolkit used by the application. The bean configured in defaultbeans.jelly uses Swing.
jguiraffe.actionManager
This bean is responsible for the actual creation of actions, menus, and tool bars as described in the chapter Events and actions. It is used in an analogous way as the bean jguiraffe.componentManager.
jguiraffe.windowManager
This bean is responsible for the actual creation of windows as described in the chapter Building windows. It is used in an analogous way as the bean jguiraffe.componentManager.
jguiraffe.builder
This bean represents the actual builder, i.e. an implementation of the Builder interface. The declaration specifies the concrete implementation class and initializes the required references to helper objects. A number of standard data type converters is configured, too.

It is possible to override some of the standard beans. This can be done by defining custom bean definition files and referencing them in the configuration file of the application. The sub section Hooks describes how this is done. If a custom bean definition file contains a bean with the same name as one of the standard beans, it replaces this standard bean. This also works for beans that are referenced by other standard beans. Therefore specific service classes used by an application can be customized.