Issue Details (XML | Word | Printable)

Key: SPR-3817
Type: Improvement Improvement
Status: Resolved Resolved
Resolution: Fixed
Priority: Major Major
Assignee: Juergen Hoeller
Reporter: Guillaume Bilodeau
Votes: 2
Watchers: 7
Operations

If you were logged in you would be able to see more operations.
Spring Framework

Transaction fails when calling DI setters on @Transactional-annotated class on startup

Created: 30/Aug/07 08:26 AM   Updated: 21/Dec/07 09:07 PM   Resolved: 08/Oct/07 05:33 PM
Component/s: SpringCORE
Affects Version/s: 2.0.6
Fix Version/s: 2.5 RC1

Time Tracking:
Not Specified

Environment: Java 5, AspectJ 1.5.x, Spring 2.0.x


 Description  « Hide

As discussed here: http://forum.springframework.org/showthread.php?p=139502

Given the following context:

. an application built with compile-time weaving using AspectJ 1.5.x,
. use of Spring 2.0.x
. a class annotated with @Transactional - not its methods,
. the same class containing one or more setters for dependency injections,
. a Spring application context declaring the above class with a singleton scope and its dependencies through property references
. the same application context using the <tx:annotation-driven /> tag

Upon loading the application context and instantiating the annotated class, the container tries to begin a transaction but fails with the following message:

java.lang.IllegalStateException: Property 'transactionManager' must be set on transaction aspect

The current behavior is understandable: the class was annotated in such a way that all its public methods should be transactional, which includes the DI setters. However this doesn't seem to be desirable, given the thrown exception.

One possible workaround is to annotate only the transactional methods (and so not the DI setter methods) instead of the class itself. The main drawback is that this leads to the duplication of the annotation and its list of rollback exceptions. It also requires that all unit tests which operate on the annotated class should provide the AnnotationTransactionAspect a mock PlatformTransactionManager on setUp().

One possible solution would be to activate the transactional aspect only after the application context is loaded. Another one would be to introduce a @NotTransactional annotation that would override the class annotation and that could be used on DI setter methods.



Juergen Hoeller added a comment - 08/Oct/07 05:33 PM

For the time being, I've revised the transaction aspect to simply skip silently if it hasn't been configured at runtime. This means that, even if it is weaved in, you can still use transactional proxying and decide to not configure the transaction aspect at all. If you configure it, it will kick it once it is fully configured; this depends on the order of your bean definitions.

The disadvantage is that you won't immediately notice when your transaction aspect is not active at runtime. I guess that's acceptable, since you won't notice when you didn't activate proxying either. Effectively this is a slight redefinition of the aspect's role: Weaving it in means that it can be active at runtime - but it doesn't have to be; the choice is up to the configuration.

As for the redundancy of rollback rules: This demands a more general solution for sharing common rollback rules. I recommend applying @Transactional at the method level, but I agree that this is only really feasible if you don't have any rollback rules - or have a way to share your rollback rules.

Juergen


Larry Chu added a comment - 21/Dec/07 07:50 PM

Can we get this backported to the 2.0.x branch?


Juergen Hoeller added a comment - 21/Dec/07 09:07 PM

This is unfortunately not a candidate for backporting to the 2.0.x branch, since the role and the semantics of the transaction aspect have been significantly revised here.

You can simply avoid @Transactional at the class level when using AspectJ weaving, annotating specific methods only. Otherwise, please upgrade to Spring 2.5!

Juergen