iBaGuice DAO

The package com.google.code.ibaguice.dao is not a DAO framework built on top of iBatis but rather contains small components that help users to avoid rewriting the same stuff in every project they need to realize a DAO layer using iBatis.

Users that want to use the DAO support of iBaGuice have to add the following dependency:

<dependencies>
    ...
    <dependency>
        <groupId>com.google.code.ibaguice</groupId>
        <artifactId>ibaguice-dao</artifactId>
        <version>XX.XX</version>
    </dependency>
    ...
</dependencies>

The Abstract DAO class

Simply, the com.google.code.ibaguice.dao.AbstractDao is an abstract class where the org.apache.ibatis.session.SqlSessionFactory is automatically injected by Google Guice.

So users want to enjoy the combined power of iBatis+Guice have just to extend that class and let Guice cretaing instances. For exampe, given the following com.acme.FooDAO implementation class:

package com.acme;

import com.google.inject.Singleton;
import com.google.code.ibaguice.dao.*;

@Singleton
public final class FooDAOImpl extends AbstractDao implements FooDAO {

    ...

}

keeping in mind the way how iBaGuice creates the iBatis bindings, users can easily obtain the instance of com.acme.FooDAO in the following way:

Class<? extends Provider<DataSource>> dataSourceProviderClass = [...];
Class<? extends Provider<TransactionFactory>> txFactoryProviderClass = [...];

Injector injector = Guice.createInjector(
    new SqlSessionFactoryModule(dataSourceProviderClass, txFactoryProviderClass),
    new Module() {
        public void configure(Binder binder) {
            binder.bind(FooDAO.class).to(FooDAOImpl.class);
        }
    });
);

FooDAO fooDAO = injector.getInstance(FooDAO.class);

@Transactional

Using a proper AOP interceptor, users can drastically reduce the boilerplate code into their DAOs.

Let's take in consideration the following code snippet:

package com.acme;

import com.google.inject.Singleton;
import com.google.code.ibaguice.dao.*;

@Singleton
public final class FooDAOImpl extends AbstractDao implements FooDAO {

    public void doFooBar() throws Exception {
        SqlSession session = this.getSqlSessionFactory().openSession(false);
        try {
            FooMapper fooMapper = session.getMapper(FooMapper.class);
            fooMapper.doFoo();

            BarMapper barMapper = session.getMapper(BarMapper.class);
            barMapper.doBar();

            session.commit();
        } catch (Throwable t) {
            session.rollback();
            throw new Exception("Something went wrong", t);
        } finally {
            session.close();
        }
    }

}

Introducing the com.google.code.ibaguice.dao.AbstractTransactionalDao class and the com.google.code.ibaguice.dao.Transactional annotation, users can eliminate recursive code patterns, trasforming the previous method in the tidy following:

package com.acme;

import com.google.inject.Singleton;
import com.google.code.ibaguice.dao.*;

@Singleton
public final class FooDAOImpl extends AbstractTransactionalDao implements FooDAO {

    @com.google.code.ibaguice.dao.Transactional
    public void doFooBar() {
        FooMapper fooMapper = this.getMapper(FooMapper.class);
        fooMapper.doFoo();

        BarMapper barMapper = this.getMapper(BarMapper.class);
        barMapper.doBar();
    }

}

to obtain this behavior, users have first to bind the interceptor using the provided com.google.code.ibaguice.dao.TransactionalModule module:

Class<? extends Provider<DataSource>> dataSourceProviderClass = [...];
Class<? extends Provider<TransactionFactory>> txFactoryProviderClass = [...];

Injector injector = Guice.createInjector(
    new SqlSessionFactoryModule(dataSourceProviderClass, txFactoryProviderClass),
    new TransactionalModule(),
    new Module() {
        public void configure(Binder binder) {
            binder.bind(FooDAO.class).to(FooDAOImpl.class);
        }
    });
);

FooDAO fooDAO = injector.getInstance(FooDAO.class);

Then, annotating methods with the com.google.code.ibaguice.dao.Transactional annotation, that supports the following parameter:

Property Default Description
executorType org.apache.ibatis.session.ExecutorType.SIMPLE the iBatis executor type
isolationLevel org.apache.ibatis.session.TransactionIsolationLevel.NONE the transaction isolation level
force false Flag to indicate that iBatis has to force the transaction commit()
rethrowExceptionsAs Exception.class rethrow caught exceptions as new Exception (maybe a proper layer exception)

The com.google.code.ibaguice.dao.AbstractTransactionalDao extends the com.google.code.ibaguice.dao.AbstractDao, so users that need to use directly the org.apache.ibatis.session.SqlSessionFactory are free to use it.

Note If, because of your system design, you're not allowed to extends the com.google.code.ibaguice.dao.AbstractTransactionalDao, but still want to enjoy the power of com.google.code.ibaguice.dao.Transactional, inject into your classes the com.google.code.ibaguice.dao.SqlSessionRegistry:

package com.acme;

import com.google.inject.Singleton;
import com.google.code.ibaguice.dao.*;

@Singleton
public final class FooDAOImpl extends MyBarClass implements FooDAO {

    @Inject
    private SqlSessionRegistry sqlSessionRegistry;

    @com.google.code.ibaguice.dao.Transactional
    public void doFooBar() {
        FooMapper fooMapper = this.sqlSessionRegistry.getMapper(FooMapper.class);
        fooMapper.doFoo();

        BarMapper barMapper = this.sqlSessionRegistry.getMapper(BarMapper.class);
        barMapper.doBar();
    }

}

Nested transactions

The com.google.code.ibaguice.dao.Transactional annotation is nicely handled to support inner transactional method declaration; given a simple service class:

class ServiceA {

    @com.google.code.ibaguice.dao.Transactional
    public void method() {
        ...
    }

}

and another one:

class ServiceB {

    @com.google.code.ibaguice.dao.Transactional
    public void method() {
        ...
    }

}

they could be called inside a new composite one:

class CompositeService {

    ServiceA serviceA;

    ServiceB serviceB;

    @com.google.code.ibaguice.dao.Transactional
    public void method() {
        ...
        serviceA.method();
        ...
        serviceB.method();
        ...
    }

}

In this case, ServiceA and ServiceB can be used isolatedly, but serviceA.method() and serviceB.method() calls in the CompositeService will be managed into the same session, even if annotated to start a new transaction.