views:

35

answers:

2

If I have a transactionally managed class, in which I have two methods e.g

void OuterMethod(Data somedata)
{
   this.InnerMethod(somedata)
}

@Transactional("mymanager")
void InnerMethod(Data somedata)
{
    //writes some things 
}

is this valid? I can't get it to write to the database for some reason, although it doesn't give me any errors.

+2  A: 

Spring does not use bytecode instrumentation to implement AOP. So it is predictable that if a method of a proxied object calls an other method in the same object, the aspect will not be applied on the method call. Spring allows however to apply the aspect on this method call by setting exposeProxy to True and using AopContext.currentProxy().

The information might be a bit dated, but to my knowledge it's still accurate (not sure about the "exposeProxy" flag though)

See http://forum.springsource.org/showthread.php?t=9926

sfussenegger
Sorry - I do not know much about Java or Spring. Do you mind clarifying that? Does it mean that I should just annotate OuterMethod?
george smiley
Yes, that's basically the essence of it. The problem is that the transaction handling is in a different object. Hence you call proxy.OuterMethod() -> service.OuterMethod() -> service.InnerMethod(), all your transaction handling is in proxy.InnerMethod(), which isn't reachable from service.OuterMethod() - not without using AopContext.currentProxy() which would be a pretty ugly workaround. So yes, annotate OuterMethod() or even both.
sfussenegger
That's right. The alternative to proxies is to use AspectJ AOP, either through load-time weaving (ugly, must replace class loader) or compile-time weaving (complicates the build process, but good tool support with Eclipse and Maven).
Henning
A: 

This is a tricky topic. When Spring finds the @Transactional annotation, it creates a proxy for your object, using either JDK interface-based proxying or CGLIB subclass-based proxying. In both cases, the proxying will only work for public methods. I may be over-simplifying things a bit, but that's the general idea.

So while a proxy object may still be generated to handle the annotated InnerMethod(), it won't actually get invoked, since non-public methods will "fall through the cracks". It would be nice if Spring warned you about this, but it doesn't.

The simple solution is to make sure your annotations are on public methods.

skaffman