How to link unitils to a spring wired datasource

Unitils provides its own DataSource. This causes problems if you want to use Spring IOC to inject your own. There is a way around this but its not elegant. In future versions of unitils I believe the team is going to provide better support for less intrusive methods. This post documents a way to use your own spring defined DataSource.

Currently there is a unitils property that allows you to specify your own SpringDataSourceFactory.

# unitils.properties

# Assign the SpringDataSourceFactory DataSource.
org.unitils.database.config.DataSourceFactory.implClassName= com.tek.design.unitils.SpringDataSourceFactory

Write your SpringDataSourceFactory and implement both DataSourceFactory and springs ApplicationContextAware interfaces. Then in the init method you will be able to fetch your spring DataSource bean from the application context using a service look up. Not ideal, but until future releases it will do just fine.

package com.tek.design.unitils;

import java.util.Properties;
import javax.sql.DataSource;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.unitils.database.config.DataSourceFactory;

/**
 *
 * Unitil's provides a way to override the default DataSourceFactory.  This class provides facility to
 * spring wire in the same datasource used by your ORM by fetching it from the ApplicationContext.
 *
 * Use the org.unitils.database.config.DataSourceFactory.implClassName property to supply this factory to unitils.
 *
 */
public class SpringDataSourceFactory implements DataSourceFactory, ApplicationContextAware {

    private static ApplicationContext appContext;

    private DataSource dataSource;

    @Override
    public DataSource createDataSource() {
        return this.dataSource;
    }

    @Override
    public void init(Properties arg0) {

        if (null == this.dataSource) {
            String dataSourceBeanName = "TekDesignDataSource";
            this.dataSource = (DataSource) appContext.getBean(dataSourceBeanName);
            if (this.dataSource == null) {
                throw new SpringBeanLookupException(DataSource.class, "Cant find bean named " + dataSourceName);
            }
        }

    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        appContext = applicationContext;

    }

}

Full unitils properties file:

# unitils.properties

# Provide a CSV of all used database schemas. ie schema1,schema2.
# The first schema name is the default one.
# If no schema name is specified in a dbunit data set the default one is used.
#
# A schema names are case sensitive when surrounded by database identifier quotes (e.g. “” for oracle)
#
# Example unitils description using a schema
#
#<dataset xmlns:frt=”FRUIT”>
#   <frt:APPLE NAME=”COX”
#                           DESCRIPTION=”[null]” />
#</dataset>
#
database.schemaNames=fruit,veg

# This property specifies the underlying DBMS implementation. Supported values are ‘oracle’, ‘db2′, ‘mysql’, ‘hsqldb’,
# ‘postgresql’, ‘derby’ and ‘mssql’. The value of this property defines which vendor specific implementations of
# DbSupport and ConstraintsDisabler are chosen.
database.dialect=oracle

# The dao tests often share the same data in the setup files, so its important to
# rollback between tests otherwise constraints will be violated.
DatabaseModule.Transactional.value.default=rollback

# Assign the SpringDataSourceFactory DataSource.
org.unitils.database.config.DataSourceFactory.implClassName=
com.tek.design.unitils.SpringDataSourceFactory

Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter
Google Buzz (aka. Google Reader)

3 thoughts on “How to link unitils to a spring wired datasource

  1. I don’t believe this will work. I’m pretty sure Unitils creates the DataSourceFactory using reflection and not via Spring. And since Spring isn’t involved in the instantiation, it never makes the DataSourceFactory “aware” of the application context.

    Am I missing something?

  2. Indeed, unitils will create the data source factory using reflection. So making it ApplicationContextAware will not have any effect since it is not loaded from a spring context.

    You could maybe do it as follows:

    implement the data source factory so that it gets a reference to the spring context somehow and then get the data source from it and return that as instance.

    Currently the whole setup with spring and unitils is not ideal.
    Spring now also has the test listener concept. In a next release we’re going to make unitils use these test listeners directly and also make it possible to do all config from spring.

    That way you can just use the spring base classes and still hook into the unitils modules.

    The unitils spring module will then become deprecated.

    brgds,
    Tim