• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Devaka Cooray
  • Liutauras Vilda
  • Jeanne Boyarsky
  • Bear Bibeault
Sheriffs:
  • Paul Clapham
  • Knute Snortum
  • Rob Spoor
Saloon Keepers:
  • Tim Moores
  • Ron McLeod
  • Piet Souris
  • Stephan van Hulst
  • Carey Brown
Bartenders:
  • Tim Holloway
  • Frits Walraven
  • Ganesh Patekar

About Spring's @Transactional and its inheritance

 
Ranch Hand
Posts: 1744
12
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi, in Spring doc

Spring recommends that you only annotate concrete classes (and methods of concrete classes) with the @Transactional annotation, as opposed to annotating interfaces. You certainly can place the @Transactional annotation on an interface (or an interface method), but this works only as you would expect it to if you are using interface-based proxies. The fact that Java annotations are not inherited from interfaces means that if you are using class-based proxies (proxy-target-class="true") or the weaving-based aspect (mode="aspectj"), then the transaction settings are not recognized by the proxying and weaving infrastructure, and the object will not be wrapped in a transactional proxy, which would be decidedly bad.



It mentions "Java annotation are not inherited from interfaces".
But @Transactional API is meta-annotated by @Inherited. It can be inherited by children classes.
If that is the case, "Java annotation are not inherited from interfaces.... then the transaction settings are not recognized by the proxy" is not true for @Transactional.
Do you think this Spring doc needs to be updated?

I would like to ask you for opinion before I ask the Spring community.
 
Saloon Keeper
Posts: 10433
223
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The @Inherited meta-annotation documentation clearly states it only works for annotated classes, not interfaces.
 
Himai Minh
Ranch Hand
Posts: 1744
12
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi, I modified the ch 8 example of Getting Started With Spring Framework 4th.
I force to use class-based proxy for BankAccountServiceImpl. I expect this proxy won't inherit the @Transactional from BankAccountService.
But my demo at https://github.com/aCodeRancher/4thEdition/tree/myTrans/chapter%208/ch08-javaconfig-hibernate/src/main/java/sample/spring/chapter08/bankapp/service
shows me that the proxy of BankAccountServiceImpl does inherit the @Transactional.

The relevant code is :







The output should have an exception at TransactionInterceptor.currentTransactionStatus(). I expect the proxy won't inherit the Transaction. But to my surprise, it works. What do you think?


in create bank account, current trans status:org.springframework.transaction.support.DefaultTransactionStatus@5099c59b
current proxy: sample.spring.chapter08.bankapp.service.BankAccountServiceImpl@4c0e426a



Reference:
http://kim.saabye-pedersen.org/2013/05/spring-annotation-on-interface-or-class.html


 
Stephan van Hulst
Saloon Keeper
Posts: 10433
223
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
It's because Spring doesn't inspect the class for transactional methods; it inspects the interface.

What happens when you change the return type of ServicesConfig.bankAccountService() to BankAccountServiceImpl?
 
Himai Minh
Ranch Hand
Posts: 1744
12
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi, Stephan,
In the ServiceConfig.java, I change the return type from BankAccountService to BankAccountServiceImpl like this:

It still works fine to my surprise.
Output:


in create bank account, current trans status:org.springframework.transaction.support.DefaultTransactionStatus@628b819d



I guess the Spring container implementation does not follow what the specification said :


Spring recommends that you only annotate concrete classes (and methods of concrete classes) with the @Transactional annotation, as opposed to annotating interfaces. You certainly can place the @Transactional annotation on an interface (or an interface method), but this works only as you would expect it to if you are using interface-based proxies. The fact that Java annotations are not inherited from interfaces means that if you are using class-based proxies (proxy-target-class="true") or the weaving-based aspect (mode="aspectj"), then the transaction settings are not recognized by the proxying and weaving infrastructure, and the object will not be wrapped in a transactional proxy, which would be decidedly bad.


 
Stephan van Hulst
Saloon Keeper
Posts: 10433
223
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
It doesn't look like your class is being proxied though. If you look at the string representation when you print the service instance, you see that it's your implementation class and not some CGLIB type.

I'm not an expert when it comes to AOP or CGLIB, but I believe that your transactional method must call a private method before the class is proxied.
 
It is sorta covered in the JavaRanch Style Guide.
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!