9

I have to use 3 different transaction managers in my webapp. So I wrote my own Annotation according to the Spring reference (Section 10.5.6.3 Custom shortcut annotations).

One annotation (for using one specific transactionmanager) looks like this:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.transaction.annotation.Transactional;

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Transactional("customer")
public @interface CustomerTX{


}

Everything is working fine when annotating my service layer with the customized @CustomerTX annotation. But I have to provide more options for my annotation, like readonly=true, rollbackFor= and so on. As you cannot "extend" an annotation (I really just need to extend the @Transactional annotation from Spring), whats the correct implementation for this?

tim.kaufner
  • 1,247
  • 5
  • 13
  • 22

2 Answers2

5

In spring 4 you can do that. As stated in the documentation

Meta-annotations can also be combined to create composed annotations. For example, the @RestController annotation from Spring MVC is composed of @Controller and @ResponseBody.

In addition, composed annotations may optionally redeclare attributes from meta-annotations to allow user customization. This can be particularly useful when you want to only expose a subset of the meta-annotation’s attributes. For example, Spring’s @SessionScope annotation hardcodes the scope name to session but still allows customization of the proxyMode.

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Scope(WebApplicationContext.SCOPE_SESSION)
public @interface SessionScope {

    /**
     * Alias for {@link Scope#proxyMode}.
     * <p>Defaults to {@link ScopedProxyMode#TARGET_CLASS}.
     */
    @AliasFor(annotation = Scope.class)
    ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;

}
C.LS
  • 1,319
  • 2
  • 17
  • 35
4

You will have to create several custom annotations, I'm afraid, one for every use case, annotating each with the exact @Transactional annotation you need.

Or you will have to write your own aspect in AspectJ ( extend org.springframework.transaction.aspectj.AbstractTransactionAspect from spring-aspects.jar ) to create your own transaction logic.


Update: this was the correct answer at the time, but as of Spring 4 and later, the answer by C.L.S should be preferred

Sean Patrick Floyd
  • 292,901
  • 67
  • 465
  • 588
  • Do you really mean I have to write something like this (assuming I just want to have set the transaction to readonly): @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Transactional(value="customer",readOnly=true) public @interface CustomerTXReadonly{ } This can't be the only working solution... – tim.kaufner Aug 31 '10 at 10:58
  • I'm afraid so, because of the limitations of annotations. As I said: either that or writing your own aspects (which I would prefer) – Sean Patrick Floyd Aug 31 '10 at 11:01
  • Thanks for your help. I'll try writing my own aspects. It's a pity that annotations aren't extendable :( – tim.kaufner Aug 31 '10 at 14:35
  • Grab a copy of `AspectJ in Action`: http://www.manning.com/laddad/ It's a very good book about AspectJ with and without Spring – Sean Patrick Floyd Aug 31 '10 at 14:40
  • Can you please elaborate on "Or you will have to write your own aspect in AspectJ ( extend org.springframework.transaction.aspectj.AbstractTransactionAspect from spring-aspects.jar ) to create your own transaction logic." How is this done? Thanks – Dikla Aug 18 '20 at 12:37
  • @Dikla keep in mind this answer is 10 years old. a lot may have changed since, and perhaps there is a better approach now. but basically, look at the .aj files in this directory: https://github.com/spring-projects/spring-framework/tree/master/spring-aspects/src/main/java/org/springframework/transaction/aspectj . Look at how AnnotationTransactionAspect.aj extends AbstractTransactionAspect.aj and add your own subclass that does what you need. this is pretty advanced stuff, there be dragons. – Sean Patrick Floyd Aug 19 '20 at 18:57
  • Thanks! That was my direction, found these classes by debugging. But how can I "tell" spring to use my subclass instead of the "normal" classes that it usually uses? – Dikla Aug 25 '20 at 06:43
  • @Dikla this is probably your starting point: https://docs.spring.io/spring/docs/current/spring-framework-reference/data-access.html#transaction-declarative-aspectj – Sean Patrick Floyd Sep 11 '20 at 00:09
  • I will look there. Thanks a lot! – Dikla Oct 13 '20 at 20:38
  • Note that the other answer https://stackoverflow.com/a/49106255/3552141 is the correct and easier way to go since a few years now (since Spring 4) – jhyot Mar 26 '21 at 09:15
  • @jhyot true. added a note to my answer – Sean Patrick Floyd Mar 26 '21 at 21:48