Posts Tagged ‘Spring’

Spring and string list injection

Saturday, January 12th, 2013

This week, I have been bitten by a surprising behavior of Spring type conversion. Let's have the following bean and Spring config.

public class Bean {
    public void setArray(String[] values) {
        System.out.println("array: " + Arrays.toString(values));
        System.out.println(values.length);
    }

    public void setList(List<String> values) {
        System.out.println("list: " + values);
        System.out.println(values.size());
    }
}
<bean class="net.javacrumbs.Bean">
    <property name="array" value="item1, item2"/>
    <property name="list" value="item1, item2"/>
</bean>

We are trying to inject a String containing comma delimited list of values. The question is whether the String will be automatically converted to list of multiple items in array/list or only one item string will be injected. Both options make sense. What do you think? What will be the length of the array/list? One or two?

The answer is surprising. The array value will be split to two Strings whereas the List will have only one element. The output will be:

array: [item1, item2]
2
list: [item1, item2]
1

It's an easy error to make but hard one to spot. If you log the values, the output is undistinguishable. If you look at the output above, the values are exactly the same. What's worse you usually do not have unit tests to test Spring configuration. In my case the bug got as far as production environment. On test environments we have got only one value in the property so the bug went unnoticed. On the production environment we have set a comma separated list of values. And of course, I have expected the array behavior while using list parameter. Silly me.

Streaming a stream

Friday, February 27th, 2009

I have another dirty trick for you. Let's imagine that you have a document server with following sophisticated interface.

public interface DocumentServer {
	/**
	 * Stores a document.
	 * @return document id
	 */
	public String storeDocument(InputStream in);
	
	/**
	 * Loads document with given id.
	 * @param id
	 * @return
	 */
	public InputStream loadDocument(String id);
}

It works well, until you realize, that you want to call the DocumentServer remotely, for example using Spring HttpInvoker.

HttpInvoker is a nice small tool, that lets you make remote method invocations over HTTP without much pain. It creates dynamic proxy, serializes all attributes using Java serialization, calls remote proxy, which deserializes arguments, calls the implementation and sends the result back in the same way. It is nice, simple and it works without any problem. You can configure it in five minutes. The downside is, that you have to have Spring Java application on both ends of the wire and all arguments that you send over the wire have to be Serializable.

And that's exactly the trouble we have with our DocumentServer. There is no standard InputStream implementation that implements serializable. Lets think about it. We need to have a stream that is able to stream itself into an ObjectOutputStream. Sounds strange, but it is quite easy. We can simply write a wrapper, that implements writeObject(ObjectOutputStream) method and that takes all the bytes from the underlying stream and writes them to the ObjectOutputStream. It is simple and it does not consume much memory.

Deserialization is much harder. We have to implement readObject(ObjectInputStream in) method, load the data and store them somewhere for later use. We can store them in the memory or in a temporary file. If the streams are larger, temporary file is better choice but we have to delete them after use and the implementation gets messy.

The good news is, that we do not have to implement it, it's already done by RMIIO library. They provide SerializableInputStream class that does exactly what we need. You just have to ignore Javadoc comment saying:

An additional layer around a RemoteInputStream which makes it Serializable and an InputStream. In general, this extra layer is not necessary and I do not recommend using this class. However, in the odd case where the callee really wants to get something which is already an InputStream, this class can be useful.

The only thing we have to do is to wrap all the streams into SerializableInputStream like this

new SerializableInputStream(new DirectRemoteInputStream(inputStream));

It can be done by hand written proxy, by dynamically generated proxy or by AOP.

Of course there are other alternatives. The easiest one is to create something like ByteArayInputStream that implements Serializable. If the streams are small enough, it's the best solution.

We can also try to use Hessian, but I had some troubles when method signatures were more complicated. And of course there is still a possibility to implement own remoting mechanism. After all, HTTP is meant to transport streams. But it would require lot of boilerplate code and I do not like boilerplate code.

Spring managed Hibernate interceptor in JPA

Saturday, January 24th, 2009

I have been trying to teach Hibernate injecting dependencies into Entities (I know, there is magic @Configurable annotation, I wanted to try it without magic). It is quite easy to do it using Hibernate interceptor (for example like this). But there is one drawback. It is not straightforward to inject interceptor into Hibernate when JPA abstraction is in the way.

It is simple to define interceptor in persistence.xml using hibernate.ejb.interceptor property. But it is only possible to specify class name, you can not inject Spring bean. If you read documentation to Spring LocalContainerEntityManagerFactoryBean there is no possibility to specify the interceptor bean there neither. But there is a way how to achieve it. First of all, you have to redefine Hibernate PersistenceProvider.

public class ConfigurableHibernatePersistence extends HibernatePersistence {
	private Interceptor interceptor;
	public Interceptor getInterceptor() {
		return interceptor;
	}

	public void setInterceptor(Interceptor interceptor) {
		this.interceptor = interceptor;
	}

	@SuppressWarnings("unchecked")
	@Override
	public EntityManagerFactory createContainerEntityManagerFactory(PersistenceUnitInfo info, Map map) {
		Ejb3Configuration cfg = new Ejb3Configuration();
		Ejb3Configuration configured = cfg.configure( info, map );
		postprocessConfiguration(info, map, configured);
		return configured != null ? configured.buildEntityManagerFactory() : null;
	}

	@SuppressWarnings("unchecked")
	protected void postprocessConfiguration(PersistenceUnitInfo info, Map map, Ejb3Configuration configured) {
		if (this.interceptor != null)
		{
			if (configured.getInterceptor()==null || EmptyInterceptor.class.equals(configured.getInterceptor().getClass()))
			{
				configured.setInterceptor(this.interceptor);
			}
			else
			{
				throw new IllegalStateException("Hibernate interceptor already set in persistence.xml ("+configured.getInterceptor()+")");
			}
		}
	}
}

(source)

Here we override method createContainerEntityManagerFactory in order to add postprocessConfiguration method call. In this method, it is possible to change Hibernate configuration as needed. Now the only thing to be done is configuring Spring to use our new PersistenceProvider. It is quite simple.

	<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
		<property name="persistenceUnitName" value="testPU" />
		<property name="dataSource" ref="dataSource" />
		<property name="persistenceProvider">
			<bean class="net.krecan.javacrumbs.jpa.interceptor.ConfigurableHibernatePersistence">
				<property name="interceptor">
					<bean class="net.krecan.javacrumbs.jpa.interceptor.SpringInjectingInterceptor"/>
				</property>
			</bean>
		</property>
	</bean>

And that all folks, we have Spring configured interceptor even when using JPA abstraction. It would be better if similar classes were in Spring or Hibernate, but it's just few lines of code so feel free to copy them if you need to. If you know easier way how to do it, please mention it in the comments below.