Jul 11, 2008

Select implementation of Spring bean in runtime

Some of you who uses Spring in your application as dependency injection framework or as development platform may be need change implementation of one particular dependency in runtime. Some examples of this need: integration testing with fake external subsystem, local and remote versions of services, mock implementation to speed up development.

I have found very useful to have such option in my applications and implemented special factory bean for this purpose:

public class SelectImplementationFactoryBean implements FactoryBean {
private String key;
private Map<String, Object> implementations;

public Object getObject() {
Object impl = implementations.get(key);
if (impl == null) {
throw new IllegalStateException("There is no implementation for key = "
+ key);
}
return impl;
}

public Class getObjectType() {
return getObject().getClass();
}

public boolean isSingleton() {
return false;
}

@Required
public void setKey(String key) {
this.key = key;
}

@Required
public void setImplementations(Map<String, Object> implementations) {
this.implementations = implementations;
}
}

Simple enough but very powerful. I will demonstrate how to use it to control database properties for integration with Hibernate:

<bean id="hibernateProperties" class="com.example.SelectImplementationFactoryBean">
<property name="key" value="${database.dialect}"/>
<property name="implementations">
<map>
<entry key="postgre">
<util:map map-class="java.util.Properties">
<entry key="hibernate.hbm2ddl.auto" value="validate"/>
<entry key="hibernate.show_sql" value="true"/>
<entry key="hibernate.dialect"
value="org.hibernate.dialect.PostgreSQLDialect"/>
<entry key="hibernate.default_schema" value="test"/>
<entry key="hibernate.cache.use_second_level_cache" value="false"/>
<entry key="hibernate.cache.provider_class"
value="org.hibernate.cache.NoCacheProvider"/>
</util:map>
</entry>
<entry key="hsqldb">
<util:map map-class="java.util.Properties">
<entry key="hibernate.hbm2ddl.auto" value="validate"/>
<entry key="hibernate.show_sql" value="true"/>
<entry key="hibernate.dialect"
value="org.hibernate.dialect.HSQLDialect"/>
<entry key="hibernate.cache.use_second_level_cache" value="false"/>
<entry key="hibernate.cache.provider_class"
value="org.hibernate.cache.NoCacheProvider"/>
</util:map>
</entry>
</map>
</property>
</bean>

Now to switch your tests to another database you should change value of the property database.dialect between postgre and hsqldb (it can be configuration properties file or system property). I hope it will save your time. Develop with pleasure!

No comments: