Java – Spring @Transactional class vs method precedence rules

javaspringtransactions

Spring says abuot @Transactional

The most derived location takes precedence when evaluating the transactional settings for a method.

Does this mean the annotation on method completely overrides annotation from class or does the omitted attributes (so defaults) does not count?

E.g.

@Transactional(isolation=Isolation.SERIALIZABLE)
public class MyService {

    @Transactional(readOnly=true)
    public void method() {
       ...
    }
}

So what is the isolation settings of the method? Is this Isolation.DEFAULT because this is the default so it implicitly overrides Isolation.SERIALIZABLE or is it Isolation.SERIALIZABLE because none was explicitly specified on method annotation?

Best Solution

The annotation at the method level completely overrides the annotation at the type-level. Any kind of hierarchy is not quite possible here. Let me explain a little more. There is no way to find out if a value was specified by the user for a specific attribute, or if a default value is being returned when you read the attributes of an annotation. So, Spring, or anybody else, cannot determine whether a specific attribute was overridden, or if a default value is being used. So, there is no way to make a decision based on the presence or absence of an attribute. For that reason, whenever you override any annotation (that is, specify it with finer granularity), you need to specify all the required attributes. So, in your case, the Isolation.DEFAULT will be the isolation applied.

However, as a aside, suppose you have your own custom annotation that specifies an empty-string as the default value for some attribute. In that case, if your class-level annotation specifies a non-empty string for that attribute, and your method-level annotation doesn't specify any value (thus using the default value: the empty-string), you could infer that the attribute-value from the class-level annotation should be used. That is, not allowing the default-value in the method-level annotation to override the user-specified value at the class-level. In any such scenario, you have to be sure that the default-value doesn't represent a valid attribute-value. In the case of the @Transactional annotations, Isolation.DEFAULT does represent a valid value and it may have been explicitly be specified by the user.