@Transactional doesn't work for instance produced by @Provides method

148 views
Skip to first unread message

Kohei Nozaki

unread,
Nov 20, 2015, 11:07:39 PM11/20/15
to google-guice
Hello,

@Transactional annotation doesn't work for an instance provided by a method annotated as @Provides. My situation is as follows. I have two classes in the reproducer. A class named FirstServiceImpl which is depends on SecondServiceImpl. These classes have following methods:

    // Method in FirstServiceImpl
    @Transactional
    public void firstSave(final MyEntity myEntity) {
        secondServiceImpl.secondSave(myEntity);
    }

    // Method in SecondServiceImpl
    public void secondSave(final MyEntity myEntity) {
        em.persist(myEntity);
    }

And FirstService is produced by a method annotated as @Provided:

    // Method in MyModule.
    @Provides
    FirstService provideFirstService(final SecondServiceImpl secondServiceImpl) {
        return new FirstServiceImpl(secondServiceImpl);
    }

In that situation, I expect transaction will begin on FirstServiceImpl#firstSave() both of following two cases:

(a) Acquire an instance by calling injector.getInstance(FirstService.class)
(b) Acquire an instance by calling injector.getInstance(FirstServiceImpl.class)

But it doesn't work for (a). It looks like that @Transactional doesn't affect for an instance produced by @Provided method. I found a workaround that putting @Transactional to SecondServiceImpl#secondSave() make it work, But unfortunately I can't make it for real code at my job.

I've pushed the reproducer to GitHub: https://github.com/lbtc-xxx/guice-persist-tx

Is this behavior by design? Or are there any better workaround?

Thanks.

Vyacheslav Rusakov

unread,
Nov 20, 2015, 11:44:14 PM11/20/15
to google-guice
Guice AOP works only on instances created by guice. You create new FirstServiceImpl(secondServiceImpl) manually and so guice can't apply transactional on it.
So it's "by design" behaviour.

Try to avoid doing guice job: let it create all instances for you. 
If you have a complex case and bean class to instantiate is known only at runtime, you can still use injector.getInstance(KnownJustNow.class) to ask guice to construct instance for you (with aop).

суббота, 21 ноября 2015 г., 10:07:39 UTC+6 пользователь Kohei Nozaki написал:

Kohei Nozaki

unread,
Nov 21, 2015, 12:04:10 AM11/21/15
to google-guice
What I actually want to do in the @Provides method is as follows:

    @Provides
    FirstService provideFirstService(SecondServiceImpl secondServiceImpl, SomeConfig config) {
        if(config.isProduction()) {
            return new FirstServiceImplForProduction(secondServiceImpl);
        }
        return new FirstServiceImplForDevelopment();
    }

And there are many client classes that expect injection of FirstService via @Inject.

Do you mean that I should invoke conditionally injector.getInstance(FirstServiceImplForProduction.class) or injector.getInstance(FirstServiceImplForDevelopment.class) instead of use @Inject in the client classes? I think it's pretty awkward... Or do you have any better idea?


2015年11月21日土曜日 13時44分14秒 UTC+9 Vyacheslav Rusakov:

Stephan Classen

unread,
Nov 21, 2015, 2:07:42 AM11/21/15
to google...@googlegroups.com
You could also check at the time the injector is created and use a conditional to decide what bindings to use.

Have a look at the method Modules.override() [1] it allows you to override bindings with other bindings. This way you don't have to use conditionals in the modules.

Here some pseudo code:
private Injector createInjector() {
if(config.isProduction()) {
return Guice.createInjector(new ProdModule());
} else {
return Guice.createInjector(override(new ProdModule()).with(new DevModule()));
}
}


[1] http://google.github.io/guice/api-docs/latest/javadoc/index.html?com/google/inject/util/Modules.html

Kohei Nozaki

unread,
Nov 21, 2015, 7:27:23 AM11/21/15
to google-guice
Stephan, Great, It looks like the way to go. Thanks!

And, Vyacheslav, Thank you for pointing that out.

2015年11月21日土曜日 16時07分42秒 UTC+9 scl:
Reply all
Reply to author
Forward
0 new messages