Spring’s FileEditor Anomaly

Following on from Vanessa Williams blog on configuring JXTA using Spring, I noticed that with the latest release of Spring (2.0.1) a problem occurred with the configuration Vanessa provided. This was not Vanessa’s fault, Spring have changed the way File properties are loaded when specified in a Spring context. This blog details the problem and the solution:

When setting a java.io.File property in a context that uses a syntax that is not ‘absolute’ and the file at the time the context is loaded does not exist (perfectly valid scenario), Spring will throw an IOException. Vanessa’s configuration looked like this:

    <bean id="netConfig" class="net.jxta.platform.NetworkConfigurator">
        <!--
            Location of the home directory
        -->
        <property name="home"><value>.jxta</value></property>
	...

The IOException dump looks like this:

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'netConfig' defined in class path resource [applicationContext-jxta-client.xml]: Error setting property values; nested exception is org.springframework.beans.PropertyBatchUpdateException; nested PropertyAccessExceptions (1) are:
PropertyAccessException 1: org.springframework.beans.TypeMismatchException: Failed to convert property value of type [java.lang.String] to required type [java.io.File] for property 'home'; nested exception is java.lang.IllegalArgumentException: Could not retrieve File for class path resource [.jxta]: class path resource [.jxta] cannot be resolved to URL because it does not exist
Caused by: org.springframework.beans.PropertyBatchUpdateException; nested PropertyAccessException details (1) are:
PropertyAccessException 1:
org.springframework.beans.TypeMismatchException: Failed to convert property value of type [java.lang.String] to required type [java.io.File] for property 'home'; nested exception is java.lang.IllegalArgumentException: Could not retrieve File for class path resource [.jxta]: class path resource [.jxta] cannot be resolved to URL because it does not exist
Caused by: java.lang.IllegalArgumentException: Could not retrieve File for class path resource [.jxta]: class path resource [.jxta] cannot be resolved to URL because it does not exist
	at org.springframework.beans.propertyeditors.FileEditor.setAsText(FileEditor.java:91)
	at org.springframework.beans.TypeConverterDelegate.convertValue(TypeConverterDelegate.java:253)
	at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:177)
	at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:127)
	at org.springframework.beans.BeanWrapperImpl.setPropertyValue(BeanWrapperImpl.java:774)
	at org.springframework.beans.BeanWrapperImpl.setPropertyValue(BeanWrapperImpl.java:607)
	at org.springframework.beans.AbstractPropertyAccessor.setPropertyValue(AbstractPropertyAccessor.java:49)
	at org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:74)
	at org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:57)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:965)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:740)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:417)
	at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:245)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:140)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:242)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:156)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:273)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:346)
	at org.springframework.context.support.ClassPathXmlApplicationContext.(ClassPathXmlApplicationContext.java:92)
	at org.springframework.context.support.ClassPathXmlApplicationContext.(ClassPathXmlApplicationContext.java:77)
	at org.springframework.context.support.ClassPathXmlApplicationContext.(ClassPathXmlApplicationContext.java:68)
	at com.marshbourdon.Application.main(ImageClientApplication.java:20)

But if the same non-existing file is referenced using an Absolute path all is fine and the underlying code can create the file at its leisure. Having looked at the source, this looks like it is down to using a ResourceEditor that has to have a file that exists rather than the java.io.File standard whereby a File can be specified but does not have to exist.

Now we could of course use Absolute paths in everything we do, but that isn’t very helpful if a user installs the application in a non-standard directory or is deployed on differing OSes. So if you prefix you non-Absolute configuration property with the ‘file:’ like so:

    <bean id="netConfig" class="net.jxta.platform.NetworkConfigurator">
        <!--
            Location of the home directory
        -->
        <property name="home"><value>file:.jxta</value></property>
	...

The whole thing magically works and your ‘.jxta’ location will be working directory specific as God and the JXTA team intended.

I am unsure whether to raise this with Spring or just let sleeping dogs lie. It seems the FileEditor class was overhauled for 2.x.x, so maybe this should be documented rather than changed, if you feel either way can you let me know before I rush in with requests?