38

Since the programmer is forced to catch all checked exception, I to throw checked exception in case of any problem. I would like to rollback on any of those expections. Writing rollbackFor=Exception.classon every @Transactional annotation is very error-prone, so I would like to tell spring, that: "whenever I write @Transactional, I mean @Transactional(rollbackFor=Exception.class)".

I know, that I could create a custom annotation, but that seems unnatural.

So is there a way to tell spring how it should handle checked excpetions globally?

pihentagy
  • 5,975
  • 9
  • 39
  • 58

4 Answers4

59

Custom Shortcut Annotations

I know, that I could create a custom annotation, but that seems unnatural.

No, this is exactly the use case for a Custom Annotation. Here's a quote from Custom Shortcut Annotations in the Spring Reference:

If you find you are repeatedly using the same attributes with @Transactional on many different methods, then Spring's meta-annotation support allows you to define custom shortcut annotations for your specific use cases.

Sample Code

And here's a sample annotation for your use case:

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Transactional(rollbackFor=Exception.class)
public @interface MyAnnotation {
}

Now annotate your services and / or methods with @MyAnnotation (you'll think of a better name). This is well-tested functionality that works by default. Why re-invent the wheel?

Sean Patrick Floyd
  • 292,901
  • 67
  • 465
  • 588
  • Ok, but isn't it confusing, that you have an annotation, which does something like `@Transactional`, but have some other naming? – pihentagy Sep 13 '10 at 20:04
  • If you really want to you can of course call your annotation `@Transactional` as well, but I guess that's very error-prone because you always have to check that you use the right import. But I agree, there's not really a better name for this than `@Transactional`. But how about `@WithTransaction` for example? – Sean Patrick Floyd Sep 13 '10 at 20:35
  • Despite of my PoV in the original question, this way seems to me the least wrong, so I accept this one. – pihentagy Sep 16 '10 at 13:15
  • This approach doesn't work for me with AspectJ. The APJClosure classes are not created when I use the "extended" annotation. Any idea why? Can I overcome this somehow? – Dikla Jul 07 '20 at 12:20
  • @Dikla that sounds like a very specific scenario. I'd recommend you ask a separate question. Also, a lot has changed over the last 10 years (since this question was asked and answered) – Sean Patrick Floyd Jul 08 '20 at 21:01
  • Thanks, here it is https://stackoverflow.com/q/62875839/59241 – Dikla Jul 13 '20 at 12:28
17

Approach with custom annotation looks good and straightforward, but if you actually don't want to use it, you can create a custom TransactionAttributeSource to modify interpretation of @Transactional:

public class RollbackForAllAnnotationTransactionAttributeSource 
    extends AnnotationTransactionAttributeSource {
    @Override
    protected TransactionAttribute determineTransactionAttribute(
            AnnotatedElement ae) {
        TransactionAttribute target = super.determineTransactionAttribute(ae);
        if (target == null) return null;
        else return new DelegatingTransactionAttribute(target) {
            @Override
            public boolean rollbackOn(Throwable ex) {
                return true;
            }
        };
    }
}

And instead of <tx:annotation-driven/> you configure it manually as follows (see source of AnnotationDrivenBeanDefinitionParser):

<bean id = "txAttributeSource"
    class = "RollbackForAllAnnotationTransactionAttributeSource" />

<bean id = "txInterceptor"
    class = "org.springframework.transaction.interceptor.TransactionInterceptor">
    <property name = "transactionManagerBeanName" value = "transactionManager" />
    <property name = "transactionAttributeSource" ref = "txAttributeSource" />
</bean>

<bean
    class = "org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor">
    <property name="transactionAttributeSource" ref = "txAttributeSource" />
    <property name = "adviceBeanName" value = "txInterceptor" />
</bean>

Also you need <aop:config/> or <aop:aspectj-autoproxy />.

However note that such overrides may be confusing for other developers who expect a normal behaviour of @Transactional.

axtavt
  • 239,438
  • 41
  • 511
  • 482
3

You can:

  • catch and wrap the checked exception into an unchecked exception - throw new RuntimeException(checkedException)
  • create a proxy around the method, using MethodInterceptor (or @AroundInvoke, or any other means to create aspects in spring), declare it to be executed before the <tx:annotation-driven /> by specifying order="1" and order="2" and catch and wrap there.
Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140
  • The first one is not an option, I would definitely force the user to catch all exceptions. Creating a proxy around the method seems to add extra complexity to the program :( – pihentagy Sep 13 '10 at 14:45
3

Looks like you can configure a transactional advice based on method name like this: (from the Spring 2.0 docs)

Exactly which Exception types mark a transaction for rollback can be configured. Find below a snippet of XML configuration that demonstrates how one would configure rollback for a checked, application-specific Exception type.

<tx:advice id="txAdvice" transaction-manager="txManager">
    <tx:attributes>
      <tx:method name="get*" read-only="false" rollback-for="NoProductInStockException"/>
      <tx:method name="*"/>
    </tx:attributes>
</tx:advice>
oksayt
  • 4,333
  • 1
  • 22
  • 41
  • 2
    that's a very good option, if he wants not to go for `@Transactional`. But both don't mix well, and one should be careful. – Bozho Sep 13 '10 at 14:52
  • +1 Yep, Bozho, that's my problem. _You cannot mix them._ I have setter injections, which are not transactionals, and I cannot predict by method name which methods are readonly. – pihentagy Sep 13 '10 at 20:07
  • I would not like to add extra magic, and rely on method naming conventions. – pihentagy Sep 15 '10 at 14:21