The Artima Developer Community
Sponsored Link

Java Buzz Forum
Guice with Spring Transactions

0 replies on 1 page.

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 0 replies on 1 page
Brian McCallister

Posts: 1282
Nickname: frums
Registered: Sep, 2003

Brian McCallister is JustaProgrammer who thinks too much.
Guice with Spring Transactions Posted: Apr 10, 2007 7:29 PM
Reply to this message Reply

This post originated from an RSS feed registered with Java Buzz by Brian McCallister.
Original Post: Guice with Spring Transactions
Feed Title: Waste of Time
Feed URL: http://kasparov.skife.org/blog/index.rss
Feed Description: A simple waste of time and weblog experiment
Latest Java Buzz Posts
Latest Java Buzz Posts by Brian McCallister
Latest Posts From Waste of Time

Advertisement

I futzed a bit with setting up Spring transaction handling in Guice. It was shockingly straightfirward :-)

So, there are several ways to do it, but I did it via having a Module export both a DBI and apply the transaction interceptor. Frankly, I probably wouldn't use this class in a real project because I would just wire it up more specific to how I needed it. However, for the common case of one data source, and annotated transactions. Bingo!

    package org.skife.jdbi.v2.unstable.guice;

    import com.google.inject.Module;
    import com.google.inject.Binder;
    import com.google.inject.matcher.Matchers;

    import javax.sql.DataSource;

    import org.springframework.transaction.PlatformTransactionManager;
    import org.springframework.transaction.interceptor.TransactionInterceptor;
    import org.springframework.transaction.annotation.Transactional;
    import org.springframework.transaction.annotation.AnnotationTransactionAttributeSource;
    import org.springframework.jdbc.datasource.DataSourceTransactionManager;
    import org.skife.jdbi.v2.spring.DBIFactoryBean;
    import org.skife.jdbi.v2.IDBI;

    public class SpringTransactionalGuiceModule implements Module
    {
        private final DataSource ds;

        public SpringTransactionalGuiceModule(final DataSource ds)
        {
            this.ds = ds;
        }

        public void configure(Binder binder)
        {
            final PlatformTransactionManager ptm = new DataSourceTransactionManager(this.ds);
            final DBIFactoryBean bean = new DBIFactoryBean();
            bean.setDataSource(ds);
            try {
                final IDBI dbi = (IDBI) bean.getObject();
                binder.bind(IDBI.class).toInstance(dbi);
            }
            catch (Exception e) {
                binder.addError(e);
                return;
            }
            binder.bindInterceptor(Matchers.any(), Matchers.annotatedWith(Transactional.class),
                                   new TransactionInterceptor(ptm, new AnnotationTransactionAttributeSource()));
        }
    }

This module reuses the jDBI Spring transaction integration glue magic stuff, hence instantiating the DBI instance via the DBIFactoryBean. It then binds Spring's TransactionInterceptor, telling it to base its tx magic on annotations via the AnnotationTransactionAttributeSource and the PlatformTransactionManager.

This could bind the platform transaction manager as well, but for now I don't need it, so I didn't.

To exercise it, I need another module which has my actual things in it, and I need to do something, like:

    public static class ThingModule implements Module
    {
        public void configure(Binder binder)
        {
            binder.bind(Thing.class);
        }
    }

    public static class Thing
    {
        private final IDBI dbi;

        @Inject
        Thing(IDBI dbi)
        {
            this.dbi = dbi;
        }

        @Transactional
        public void excute(final Callback cb)
        {
            final Handle handle = DBIUtil.getHandle(dbi);
            cb.call(handle);
        }
    }

    public interface Callback
    {
        public void call(Handle handle);
    }

The only transactional element is the Thing#excute method, and it is using the Spring 2.0 @Transactional annotation.

I like to use callbacks for testing transactional stuff like this, reduces the clutter. The only really nasty bit to this, imho, is the Handle handle = DBIUtil.getHandle(dbi); which uses the Spring idiom of having a static helper to get transactionally bound resources. I dislike it, but it is Spring idiom, and I am reusing the jDBI Spring stuff, so... c'est la vie for now.

Setting it up and running, then is just:

    public void setUp() throws Exception
    {
        super.setUp();
        this.guice = Guice.createInjector(new ThingModule(),
                           new SpringTransactionalGuiceModule(Tools.getDataSource()));
    }

    public void testFoo() throws Exception
    {
        final Thing thing = guice.getInstance(Thing.class);
        assertNotNull(thing);

        try {
            thing.excute(new Callback()
            {
                public void call(Handle handle)
                {
                    assertTrue(handle.isInTransaction());
                    handle.insert("insert into something (id, name) values (?, ?)", 1, "Rob");
                    throw new IllegalStateException();
                }
            });
            fail("Should have thrown an exception");
        }
        catch (IllegalStateException e) {
            assertTrue(true);
        }
        final Handle h = openHandle();
        assertFalse(h.isInTransaction());
        final List<String> names = h.createQuery("select name from something")
                .map(StringMapper.FIRST)
                .list();
        assertEquals(0, names.size());
    }

And it all works! Woo hoo!

A drawback, and I haven't found a way around this, is that you cannot provide dependencies to interceptors, so the data source must be available outside the injector. Bob says it will be in the next release though, so woot!

Read: Guice with Spring Transactions

Topic: Lighthouse Pro: Free Software Development Management Previous Topic   Next Topic Topic: GPLv3 vs. Apache License 2.0: Irreconcilable Differences?

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use