Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it safe to use a Spring @Transactional annotation on a Java 8 default interface method?

The Spring documentation recommends against putting @Transactional annotations on interface methods because interface annotations are not inherited by classes. However, with Java 8 we can provide a concrete default implementation in the interface. If such a default interface method needs to be the transactional boundary, we have no other choice: we have to put the @Transactional annotation on the interface method.

Will this work (i.e. will spring respect the transaction boundary in this case)? If so, are there any hidden pitfalls to this approach?

like image 758
JMB Avatar asked Dec 09 '13 00:12

JMB


People also ask

Can I use @transactional at interface?

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.

When should we use @transactional annotation?

The @Transactional annotation is the metadata that specifies the semantics of the transactions on a method. We have two ways to rollback a transaction: declarative and programmatic. In the declarative approach, we annotate the methods with the @Transactional annotation.

Is it sufficient to annotate the classes with the @transactional annotation?

You can place the @Transactional annotation before an interface definition, a method on an interface, a class definition, or a public method on a class. However, the mere presence of the @Transactional annotation is not enough to activate the transactional behavior.

Can we use @transactional on private methods?

The answer your question is no - @Transactional will have no effect if used to annotate private methods. The proxy generator will ignore them. When using proxies, you should apply the @Transactional annotation only to methods with public visibility.


1 Answers

Spring uses (among others) a BeanFactoryTransactionAttributeSourceAdvisor as an Advisor when generating a proxy bean for classes annotated with or containing methods annotated with @Transactional.

When the time comes to proxy it, it uses the bean's class type (with CGLIB) to generate the proxy. So we want to see if the default method annotated with @Transactional will be visible from the implementing class' point of view.

Here's a Java 8 SSCCE

public static void main(String[] args) throws Exception{
    Class<?> randomImplClass = RandomImpl.class;
    System.out.println(randomImplClass);
    Easy annotation = randomImplClass.getAnnotation(Easy.class);
    System.out.println("Class: " + randomImplClass);
    System.out.println("Class Annotation: " + annotation);

    Method method = randomImplClass.getMethod("doRandom");
    annotation = method.getAnnotation(Easy.class);
    System.out.println("Method: " + method);
    System.out.println("Method Annotation: " + annotation);
}

public static class RandomImpl implements Random{}
@Easy
interface Random {
    @Easy
    default void doRandom() {System.out.println("testing");};
}

@Target(value = {METHOD, TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Easy {}

which prints

class TestEnhancer$RandomImpl
Class: class TestEnhancer$RandomImpl
Class Annotation: null
Method: public default void TestEnhancer$Random.doRandom()
Method Annotation: @TestEnhancer$Easy()

Indicating that the annotation was inherited for the interface's method. It seems, therefore, that Spring will be able to add @Transactional behavior when the class has not overriden the default method. If it has overriden it, then annotations are not inherited.

like image 55
Sotirios Delimanolis Avatar answered Sep 19 '22 18:09

Sotirios Delimanolis