Tuesday 12 May 2009

Spring FAIL - incomplete documentation on JibxMarshaller from spring-oxm library

This issue is prevalent in a lot of open source projects: inadequate
documentation and non-existent examples.

<bean id="jibxMarshaller"
class="org.springframework.oxm.jibx.JibxMarshaller">
<property name="targetClass" value="au.com.company.JOB"/>
<property name="indent" value="4" />
<property name="bindingName" value="jibx_binding" />
</bean>


The javadoc for setBindingName() in JibxMarshaller simply says:

/** Sets the optional binding name for this instance. */

There is no indication what it actually means - is the bindingName the
same as the binding file? Should I be indicating the location of the
file??

I try this:

<property name="bindingName" value="classpath:jibx-binding.xml" />

and I get

Caused by: org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'jibxMarshaller' defined in class path
resource [batchContext.xml]: Invocation of init method failed; nested
exception is org.springframework.oxm.jibx.JibxSystemException: Binding
'classpath:jibx-binding.xml' not found for class
au.com.careerone.xmlbinding.adicio.JOB; nested exception is
org.jibx.runtime.JiBXException: Binding 'classpath:jibx-binding.xml'
not found for class au.com.careerone.xmlbinding.adicio.JOB
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1337)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:473)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:409)
at java.security.AccessController.doPrivileged(Native Method)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:380)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:264)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:221)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:261)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:185)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:164)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:269)
... 32 more
Caused by: org.springframework.oxm.jibx.JibxSystemException: Binding
'classpath:jibx-binding.xml' not found for class
au.com.careerone.xmlbinding.adicio.JOB; nested exception is
org.jibx.runtime.JiBXException: Binding 'classpath:jibx-binding.xml'
not found for class au.com.careerone.xmlbinding.adicio.JOB
at org.springframework.oxm.jibx.JibxMarshaller.afterPropertiesSet(JibxMarshaller.java:137)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1368)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1334)
... 42 more
Caused by: org.jibx.runtime.JiBXException: Binding
'classpath:jibx-binding.xml' not found for class
au.com.careerone.xmlbinding.adicio.JOB
at org.jibx.runtime.BindingDirectory.getFactory(BindingDirectory.java:180)
at org.jibx.runtime.BindingDirectory.getFactory(BindingDirectory.java:197)
at org.springframework.oxm.jibx.JibxMarshaller.afterPropertiesSet(JibxMarshaller.java:130)
... 44 more


I then tried putting in the mapping name, even though it doesn't
really make much sense:


<property name="bindingName" value="JOB" />

Still no dice.

I look in the source for JibxMarshaller, and find this line where
bindingName is used:

bindingFactory = BindingDirectory.getFactory(bindingName, targetClass);

I look in the Jibx class BindingDirectory, and find:

public static IBindingFactory getFactory(String name, Class clas,
ClassLoader loader) throws JiBXException {
String list = getBindingList(clas);
String match = GENERATE_PREFIX + name +
BINDINGFACTORY_SUFFIX + '|';
int index = list.indexOf(match);


where GENERATE_PREFIX and BINDINGFACTORY_SUFFIX are:

/** Prefix used in all code generation for methods and classes. */
public static final String GENERATE_PREFIX = "JiBX_";

/** Suffix of binding factory name. */
public static final String BINDINGFACTORY_SUFFIX = "Factory";


Then I look around in my /target directory (I am using Maven), and see
that there is a class called:

JiBX_jibx_bindingFactory.class

Opening this in Notepad++, I find a string:


au/com/careerone/xmlbinding/adicio/JiBX_jibx_bindingFactory

So it looks like Jibx first converts the name of the binding file into
Java class format, and the '-' in jibx-binding becomes an underscore.

So we get: jibx_binding

But was this documented anywhere? No!

This Jibx bug helped me figure it out:

https://svn.sxc.codehaus.org/browse/JIBX-210

Oh well.