JICE and Spring Framework

Author: Timo Laitinen
Date: 2005-06-30

Contents

4.11.Summary

1. About this document

Spring framework is an advanced and popular J2EE Application Framework that provides, among other features, also an XML-based application configuration solution. This document analyzes the similarities and differences between JICE and Spring Framework and studies how these two technologies could be used together.

The first part of this document will compare the configuration capabilities of JICE and Spring. The comparison shows that:

The last part analyzes shortly how JICE and Spring could be used together. The intention is to find a solution that would combine the best of both worlds. This would help both Spring and JICE:

My knowledge about Spring framework is quite limited. So please forgive me if I have got some of the facts wrong. Feedback from this document is welcome and can be given at the forums:

JICE discussion forums

2. Spring BeanFactory and ApplicationContext

Spring framework consists of multiple modules that ease the creation of J2EE applications. The modules provide tools for configuration management, Aspect oriented programming (AOP), transaction management, JDBC/Hibernate/JDO programming, web presentation layers, etc.

BeanFactory and ApplicationContext are the core of Spring.

The XmlBeanFactory is almost identical to JICE. Both define an XML format for configuring Java objects and provide tools for processing the XML data into living Java objects.

ApplicationContext provides mostly functionality for areas that JICE doesn't cover.

3. Object deployment models

Both JICE and the BeanFactory of Spring create and initialize objects that are used in a Java application. JICE could in principle create the whole application itself, but usually only parts of the application objects are created by JICE.

From the view point of JICE and BeanFactory, rest of the Java application is a client that requests objects from them. JICE and BeanFactory create the objects on request and deliver them to the client.

The term object deployment model is used in this context for referring both to the way the clients retrieve the objects from JICE and BeanFactory and to the way JICE and BeanFactory internally deliver the objects to the client. An object is deployed when it is delivered to the client.

3.1.Object deployment model of BeanFactory

The process of obtaining an object (a bean in Spring) from BeanFactory has two phases:

  1. obtain a BeanFactory instance
  2. ask the BeanFactory for a bean by name

3.1.1.Obtaining a BeanFactory instance

The client can create a BeanFactory instance manually. First, the correct implementation needs to chosen (for example a XmlBeanFactory or a XmlWebApplicationContext). Then the BeanFactory needs to be initialized. BeanFactory implementations usually have various parameters to be configured like the location of the XML file and the BeanPostProcessors used, for example.

ApplicationContext and its subclasses provide various automations for initializing BeanFactory instances. In web applications for example, the context may be initialized by a servlet that reads a certain XML file in the WEB-INF directory.

I didn't quite understand how the initialized BeanFactory instances are actually obtained, however. Perhaps they are put in the ServletContext in web applications.

3.1.2.Asking for a bean

A single BeanFactory contains multiple beans. Once the client has got a hold of a BeanFactory instance, it can obtain a specific application object by asking the bean by name.

BeanFactory can deploy any bean either as a singleton or as a non-singleton. If a bean is deployed as a singleton, only a single instance of the bean will be created, and every query for the bean will yield the the same instance. A non-singleton deployment means that a new instance is created with the same settings on every query.

The deployment method of a bean can be specified in the XML configuration. The singleton method is more common than the non-singleton.

Spring supports also hierarchical bean definitions - Bean factories can be nested in a hierarchy and child factories may override the definitions of the parent factories.

3.2.Object deployment model in JICE

The object deployment model is very simple. Two phases can be identified:

  1. Specify the location of the JIC file and the parameters.
  2. Obtain the resulting object by letting the JIC Engine to process the file.

Everything else is left for the client application. JICE has no built-in support for locating the JIC files or loading them automatically. JICE doesn't store or cache the objects it creates as in the singleton-deployment pattern of BeanFactory. Expressed in BeanFactory terms, every object is a non-singleton.

In principle, every XML file specifies a single object, although this object can of course be a collection of objects. The XML files don't form a hierarchy, but the client may override definitions in a JIC file through parameters. Of course, the parameters could be defined in another JIC file, but JICE doesn't yet have any built-in support for achieving this.

3.3.Conclusions

The object deployment model of BeanFactory is far more evolved than in JICE. Spring is a complete J2EE application framework, so it is natural that it covers more aspects.

JICE doesn't actually provide any object deployment model at all. JICE is specialized only in the XML-based configuration and provides no additional functionality. This approach has also advantages - JICE isn't locked to a single kind of deployment model - but it is obvious that as a configuration tool, JICE would profit from a more advanced object deployment model. Currently the applications using JICE have to provide the missing functionality by themselves.

4. XML configuration capabilities

This section studies how JICE and BeanFactory initialize objects and how the object configuration is expressed in XML. Some basic object initialization capabilities are demonstrated by examples.

All the Spring examples are taken from the Spring documentation:

Spring Reference Documentation, version 1.1.2. http://www.springframework.org/docs/reference/index.html. (Referenced 2004-10-28)

4.1.Creating an object to be initialized

In Java, 3 different ways for object creation can be identified:

  1. Calling the constructor of a class with the new operation
  2. Obtaining the object from a static factory method.
  3. Obtaining the object from a instance factory method.

All methods may or may not require some parameters to be present.

4.1.1.Calling an empty constructor

Spring:

<bean id="exampleBean"
      class="examples.ExampleBean"/>
<bean name="anotherExample"
      class="examples.ExampleBeanTwo"/> 

JICE: The JICE version solution is almost identical to the Spring version. The constructor can be called explicitly by using new operator or the constructor call can be derived from the class attribute.

<bean class="examples.ExampleBean"/>
<bean class="examples.ExampleBean" instance="new examples.ExampleBean()"/>

4.1.2.Calling a constructor with parameters

Spring: Constructor arguments are defined with inner <constructor-arg> elements. Other beans are referenced with their id.

<bean id="exampleBean" class="examples.ExampleBean">
    <constructor-arg><ref bean="anotherExampleBean"/></constructor-arg>
    <constructor-arg><ref bean="yetAnotherBean"/></constructor-arg>
    <constructor-arg><value>1</value></constructor-arg>
</bean>

<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>

JICE: the attribute args defines which of the child elements are constructor arguments.

<exampleBean class="examples.ExampleBean" args="beanOne, beanTwo, integer">
<beanOne class="examples.AnotherBean"/>
<beanTwo class="examples.YetAnotherBean"/>
<integer class="int">1</integer>
</exampleBean>

Also objects defined outside an element may be referenced by their name if they are declared to be variables. Because JIC Engine processes the elements in sequence, the referenced objects must be defined before they are used.

<container class="examples.ExampleBean" instance="exampleBean" vars="anoterExampleBean, yetAnotherBean">
<anotherExampleBean class="examples.AnotherBean"/>
<yetAnotherBean class="examples.YetAnotherBean"/>
<exampleBean class="examples.ExampleBean" args="beanOne, beanTwo, integer">
<beanOne class="examples.AnotherBean" instance="anotherExampleBean"/>
<beanTwo class="examples.AnotherBean" instance="yetAnotherBean"/>
<integer class="int">1</integer>
</exampleBean>
</container>

Objects can also be referenced directly in the args attribute. There's no need for the inner elements.

<container class="examples.ExampleBean" instance="exampleBean" vars="anoterExampleBean, yetAnotherBean">
<anotherExampleBean class="examples.AnotherBean"/>
<yetAnotherBean class="examples.YetAnotherBean"/>
<exampleBean class="examples.ExampleBean" args="anoterExampleBean, yetAnotherBean, integer">
<integer class="int">1</integer>
</exampleBean>
</container>

4.1.3.Obtaining an object from a static factory method without parameters

Spring: Static factory method is defined with the attributes class and factory-method. The semantics of the class attribute has changed - it refers now to the class containing the factory method, not the class of the bean instance.

<bean id="exampleBean"
      class="examples.ExampleBean2"
      factory-method="createInstance"/>

JICE: The method call is expressed in the attribute instance.

<exampleBean class="examples.ExampleBean" instance="examples.ExampleBean2.createInstance()"/>

4.1.4.Obtaining an object from a static factory method with parameters

Spring: The parameters for the factory method are provided with the <constructor-arg> elements.

<bean id="exampleBean" class="examples.ExampleBean"
      factory-method="createInstance">
    <constructor-arg><ref bean="anotherExampleBean"/></constructor-arg>
    <constructor-arg><ref bean="yetAnotherBean"/></constructor-arg>
    <constructor-arg><value>1</value></constructor-arg>
</bean>

<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>

JICE: parameters are defined as part of the method call in the instance attribute.

<exampleBean class="examples.ExampleBean" instance="examples.ExampleBean.createInstance(beanOne, beanTwo, integer)">
<beanOne class="examples.AnotherBean"/>
<beanTwo class="examples.YetAnotherBean"/>
<integer class="int">1</integer>
</exampleBean>

Again, argument objects may also be defined outside the element <exampleBean>.

<container class="examples.ExampleBean" instance="exampleBean" vars="anoterExampleBean, yetAnotherBean">
<anotherExampleBean class="examples.AnotherBean"/>
<yetAnotherBean class="examples.YetAnotherBean"/>
<exampleBean class="examples.ExampleBean" instance="examples.ExampleBean.createInstance(beanOne, beanTwo, integer)">
<integer class="int">1</integer>
</exampleBean>
</container>

4.1.5.Obtaining an object from an instance factory method

Spring: The attributes factory-bean and factory-method are used.

<!-- The factory bean, which contains a method called
     createInstance -->
<bean id="myFactoryBean"
      class="...">
  ...
</bean>
<!-- The bean to be created via the factory bean -->
<bean id="exampleBean"
      factory-bean="myFactoryBean"
      factory-method="createInstance"/>

JICE: The call to the instance factory method is specified in the instance attribute, like the case with the static factory.

<myFactoryBean class="..."> </myFactoryBean>
<exampleBean class="examples.ExampleBean" instance="myFactoryBean.createInstance()"/>

The configuration of the factory instance can also be defined inside the <exampleBean>.

<exampleBean class="examples.ExampleBean" instance="myFactoryBean.createInstance()">
<myFactoryBean class="..."> </myFactoryBean>
</exampleBean>

4.2.Calling methods of an object to be initialized

After the object is obtained, the initialization of the object may involve method invocations. The methods to be invoked can separated to property setters and other methods.

4.2.1.Setting properties

Setting a property means calling the respective setXXX() method of the object.

Spring: The <property> element is used for setting properties. The element <value> specifies the value of the property. Spring uses property editors for converting the String inside the <value> element into the required Java object.

<bean id="exampleBean" class="examples.ExampleBean">
    <property name="beanOne"><ref bean="anotherExampleBean"/></property>
    <property name="beanTwo"><ref bean="yetAnotherBean"/></property>
    <property name="integerProperty"><value>1</value></property>
</bean>

<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>

JICE: Inner elements that are not constructor parameters are used for setting properties. All conversions from String values to other objects must be set explicitly. In this case, the attribute class="int" declares, that the CDATA section of the <integerProperty> is converted to java.lang.Integer and ultimately to int.

<exampleBean class="examples.ExampleBean">
<beanOne class="examples.AnotherBean"/>
<beanTwo class="examples.YetAnotherBean"/>
<integerProperty class="int">1</integerProperty>
</exampleBean>

4.2.2.Calling a method

Spring: Only a single method called initialization method can be called during the initialization of a bean. (don't know whether the method can be given parameters or not. the example didn't mention them)

 <bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/>

JICE: The method call is defined with a child element that has the attribute action.

<exampleInitBean class="examples.ExampleBean">
<call-init action="init()"/>
</exampleInitBean>

The action attribute can be used for calling any method with any kind of parameters. There is also no restrictions on how many method calls there are.

Here is an example that calls the add(int,int) method of class java.util.Calendar,

<calendar class="java.util.Calendar" instance="java.util.Calendar.getInstance()">
<lenient class="boolean">true</lenient>
<addAYear action="add(field,amount)">
<field class="int" instance="java.util.Calendar.YEAR"/>
<amount class="int">1</amount>
</addAYear>
<addAMonth action="add(field,amount)">
<field class="int" instance="java.util.Calendar.MONTH"/>
<amount class="int">1</amount>
</addAMonth>
</calendar>

4.3.Obtaining the return-value of a method call

Spring: This example shows how to obtain the value of the system property java.version.

<bean id="sysProps" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
  <property name="targetClass"><value>java.lang.System</value></property>
  <property name="targetMethod"><value>getProperties</value></property>
</bean>
<bean id="javaVersion" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
  <property name="targetObject"><ref local="sysProps"/></property>
  <property name="targetMethod"><value>getProperty</value></property>
  <property name="arguments">
    <list>
      <value>java.version</value>
    </list>
  </property>
</bean>

JICE: The same situation is handled with the following JIC script:

<javaVersion class="java.lang.String" instance="systemProperties.getProperty(propertyName)">
<systemProperties class="java.util.Properties" instance="java.lang.System.getProperties()"/>
<propertyName>java.version</propertyName>
</javaVersion>

4.4.Obtaining a value of a static field

Spring: not possible.

JICE: The static field can be specified in the instance attribute:

<alignment instance="java.awt.FlowLayout.CENTER"/>

4.5.Create an array

Spring: no array support.

JICE: element type array constructs an array. Both object and primitive arrays are supported.

<words class="java.lang.String[]" type="array">
<word>hello</word>
<word>world</word>
</words>
<numbers class="int[]" type="array">
<number class="int">1</number>
<number class="int">2</number>
<number class="int">3</number>
</numbers>

4.6.Create a collection

Both Spring and JICE have structures for creating lists and maps. Spring has special <list> and <map> elements. In JICE a list or map can be populated manually (by calling add() or put()) or by using built-in element types.

Examples are not shown - there are enough examples already.

4.7.Null values

Spring: There is an element <null> that can be used for setting the value of a property or constructor parameter to null.

JICE: No null support.

4.8.Overriding definitions in the XML file

Spring: Bean factories can form an hierarchy. Child factories may override definitions of the parent factory.

JICE: Only elements that are marked to be overridable can be overridden. Client provides the overriding values i.e. build parameters to the JIC Engine when the processing of a XML file starts.

4.9.Conditionality Support

Spring: no.

JICE: has a simple if and switch structures that make it possible to define some logic in the JIC Files.

4.10.User defined types

Spring: Bean definitions may have a parent definition. The child definition inherits the definitions of the parent. This makes the parent definition function as a custom type.

JICE: user-defined factories may be declared and used in JIC Files. factories resemble functions - they receive parameters and return an object.

4.11.Summary

Feature JICE Spring (XmlBeanFactory)
Can instantiate any class with the new operation. yes. yes.
Can obtain an object from a static factory method. yes. yes.
Can obtain an object from an instance factory method. yes. yes.
Can set any property by calling a respective setXXX() method. yes. yes.
Can call any public methods of an object. yes. no. (Can call only a single initialization method without parameters.)
Can call a desctruction method. no. yes. (Can call a single desctruction method without parameters, if the bean is deployed as a singleton.)
Can obtain the return-value of a method call. yes. yes.
Constants support - can obtain the value of a static field. yes. no.
Can create object and primitive arrays yes. no.
Can create and populate collections yes. yes.
null support no. yes.
Definitions in the XML file can be overridden. partial. (Only elements that are declared to be overridable can be overridden) yes.
Conditionality yes. no.
User defined types. yes. yes.

4.12.Conclusions

4.12.8.Spring is biased towards beans

The XML configuration capabilities of Spring are biased towards beans. It is easy to instantiate an object and set its properties, but there is a poor support for non-bean-like aspects:

Although the bean model is popular, only a part of the existing Java classes are beans. Non-bean-like features are also needed.

JICE supports beans but is not limited to them. JICE handles both bean-like and non-bean-like situations equally well. JICE has much more object initialization features than Spring.

Spring has 2 important features that JICE doesn't currently provide:

  1. Support for null values.
  2. User defined types.

These features would certainly be useful in JICE also.

4.12.9.XML code of JICE is closer to the application domain

The XML format of Spring contains elements like <bean>, <property>, <value>, <ref>, <constructor-arg>, etc. The element names are abstract and not related to the application domain - the application that is being configured probably doesn't have classes or properties named bean, property, value, constructor-arg.

In JICE the XML element names depend on the API of the application and on the naming convention of the developer. The element names are always related to the application domain. This makes the XML data more descriptive.

5. Using JICE and Spring together

Because the XML configuration capabilities of JICE are better than those of Spring, JICE could be used instead of the Spring's XmlBeanFactory component.

The BeanFactory and ApplicationContext have no direct dependencies on other Spring modules. The other modules are used through their API: the classes are referred from the XML configuration files.

Because JICE can also configure any existing Java API, the other Spring modules can be used from JIC files in the same manner as they are now used from the XML files of XmlBeanFactory. Instead of writing an XML file for XmlBeanFactory, a JIC file would be written.

Of course, the objects defined in the JIC files must be made available. This is the most problematic aspect in the integration of JICE and Spring. There are two alternatives:

  1. loose integration: JICE is used through its own interface.
  2. JICE plugin: JICE is used through the BeanFactory interface. A JICE-based implementation of the BeanFactory would be created (a JICEBeanFactory or something).

The first one is simpler and can be done already. However, many of the existing Java classes using Spring are already constructed based on the BeanFactory and ApplicationContext interfaces. All this code would have to be refactored, which makes the alternative 1. a poor choice. (especially if the other Spring modules assume that BeanFactory and ApplicationContext are used for configuration. I haven't studied this yet.)

The plugin-alternative would provide a better solution. The plugin would just have to created first. There isn't currently any clear plan on how and when such a plugin would be implemented.

5.1.About implementing the JICE plugin

If only BeanFactory interface would need to be created, the plugin would be easy to implement.

However, the BeanFactory interface has multiple subinterfaces, ApplicationContext being probably the most important one. Perhaps a plugin implementing some of the subinterfaces would be needed? I don't yet know whether this would be difficult or not.

The biggest obstacles in creating the plugin are probably related to:

If you have any suggestions or ideas on how such a JICE plugin should be implemented, please share your thoughts on the forum:

JICE discussion forums