Spring #Transactional class vs method precedence rules - java

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?

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.

Related

How to target methods declared in a controller subclass whilst avoiding ambigous mapping?

I am trying to use AspectJ for logging in a Spring Boot project. The latter has been set up with a controller class that handles the initial request for a particular document through a related REST controller. This controller class is extended by specific classes for each document, which assemble the end product; inheritance was not my idea.
To measure performance I want to log execution time for individual methods by using an #Around advice. However, even when the functions are individually annotated, those in the subclass are not advised. Methods further in the call stack that are not inherited from the initial controller class are not ignored. The relevant subclass methods are public and they are not inherited from the superclass.
Logging the execution time of the controller method is meant to provide the overall duration. Information with respect to subsequent functions is supposed to indicate possible bottlenecks. How can I include the methods declared in the subclass?
Confidentiality precludes sharing specifics, but the relevant aspects of the class structure can be conveyed using generic names:
[
To follow best practices I always intended to implement custom annotations to be used in pointcuts. Nevertheless, initially, I used signature based pointcuts and their combinations. Ignoring package elements of the pointcut declaration:
#Pointcut("execution(public String Controller.*(..)")
public void controllerPointcut() {}
This approach captures the controller methods, as do similar declarations for the reader classes. However such pointcuts are simply ignored in the case of the subclass. Using the + symbol to target child classes does not help. The documentation indicates that inherited or declared methods in a subclass can be targeted by signature. In the specific case this results in an IllegalStateException due to ambiguous mapping, as does the use of a class level annotation, unsurprisingly.
I only need to log two methods in the child classes, so I hoped to target them directly with a common annotation, which I also added to the controller and reader methods. The pattern, excluding package elements is:
#Pointcut("#annotation(LoggableDuration)")
public void readerControllerPointcut() {}
The functions in the latter two are being advised, so the annotation itself is not the problem. Nevertheless, the implementation has been added below. For thoroughness, I used a combined approach as well. The controller methods were targeted with the kind of signature approach shown above and for the rest an annotation was used. The result is the same. The problem seems to be some element of how AspectJ deals with inheritance that I have not been able to discover. However, I did expect that annotating individual methods could possibly allow me to avoid any such considerations.
#Component
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface LoggableDuration {}
Edit: It seems that Spring Boot was not picking up the subclass. Adding the #Component annotation allows AspectJ to advise the desired methods as does a class level custom annotation with ElementType.Type as the #Target value. However, both lead to an IllegalStateException: ambiguous mapping, presumably because of the inheritance of the Rest controllers. I managed to target the subclass methods with execution based pointcuts, which were not ignored. But, this caused the aforementioned exception to appear again.

Is it possible to have a Java annotation that doesn't apply to any class, method, field, etc. Just the annotation itself generating code

Are there such things as Java annotations that aren't tied to any class, method, field, etc.?
Like just writing
#MyAnnotation(someParameter=value, ...)
by itself, and it generates code.
It seems like ExecutableType might define what kinds of "elements" an annotation can annotate, but I'm not sure. If that's true, then ExecutableType derives from TypeMirror, one of whose members are NoType. So maybe it's possible? But I cannot find an example of this.
You cannot have a stand-alone annotation in Java.
Annotations can be applied to different things, for example: types, methods, fields, local variables, packages, method parameters and also on annotation definitions.
One annotation that is meant to be used on annotation definitions (therefore it's called a "meta-annotation") is #Target, which you use to indicate on what things the annotation you are defining is allowed to be used. You do this by specifying one or more element types as an argument to the #Target annotation - see the API docs of java.lang.annotation.ElementType.
The Java Language Specification paragraph 9.6.4.1 explains what annotations can be used on in more detail.

Is it safe to remove #Named annotations without a name?

A tonne of code at my company uses the javax.inject.Named annotation with the default value, which the Javadoc indicates is the empty string "".
For example:
#Named
public class Foo {
...
}
This does not appear to add any value, since the empty string doesn't have any semantic meaning. If I remove the #Named annotations will there be any harmful effects?
The question What is javax.inject.Named annotation supposed to be used for? describes how #Named functions, but doesn't explain any special significance of the empty string, or why it would be necessary or beneficial to omit the actual name.
The question When should you explicitly name a Managed Bean? likewise talks about when you would want to use names to differentiate injectable beans, but doesn't provide any rationale for the use of the empty string as a name.
Can I delete these un-named #Named annotations without breaking anything?
#Named (javax.inject.Named) is equivalent of #Component (org.springframework.stereotype.Component).
When used to annotated a class, it indicates that the class will be scanned and registered. If name is not given, DI framework will use the class type when injecting dependencies.
In short, you can't remove those #Named annotation. If you do, everything will be compiled as normal. However, at runtime, you'll get runtime error something like cannot find bean xyz.
It's impossible to know if you will break anything without analyzing all the code that constructs injection keys and all the code that injects any of these bindings.
In some JSR-330 implementations (e.g. Dagger) it's not possible to use a #Named annotation with a value constructed at runtime, but in other implementations (e.g. Guice) it is possible and in fact commonly done.
For example, I could imagine a Guice module like:
public final class DynamicFooModule extends AbstractModule {
private final String whichFoo;
public DynamicFooModule(String whichFoo) {
this.whichFoo = whichFoo;
}
#Override
protected void configure() {
Key<Foo> fooKey = Key.get(Foo.class, Names.named(whichFoo));
Provider<Foo> fooProvider = getProvider(fooKey);
bind(Foo.class).toProvider(fooProvider);
}
}
This provides a binding for an unannotated Foo which delegates to a #Named(x) Foo, where x is determined by a constructor argument to the module -- which could be constructed at runtime, or derived from some default somewhere, etc.
You could imagine code building an injector like:
Injector injector = Guice.createInjector(
...,
new DynamicFooModule(getSelectedFooConfig()),
...);
Where getSelectedFooConfig() might return "" as a default or fallback.
In a situation like that, #Named without any name could be a reasonable fallback value to use. If your application is doing anything like that, then it is not safe to remove the #Named bindings, because an un-annotated binding is not equivalent to a binding with an empty string.
I still would argue that this is not a good design: it would be better to use a dedicated qualifier annotation for this purpose (e.g. #ConfigBased("foo-config")) rather than just using #Named. If you were doing that then you could at least identify which strings were being used (or, better yet, eschew strings and use an enum instead).

Default value for #TransactionAttribute

I am using EcllipseLink 2.5 in my project.
Default value for #TransactionAttribute, is required.
If we define SessionBean as TransactionManagementType CONTAINER, do we still need to add #TransactionAttribute annotation for every method in SessionBean to support transactions?
Is there anyway to add default configuration for all SessionBeans or whole class?
I don't want to add #TransactionAttribute with every method in class.
Any help would be much appreciated.
Thanks
Default value for TransactionAttribute is REQUIRED. REQUIRED is also the default if no TransactionAttribute annotation is used and the EJB in question uses container managed transactions.
Marking the EJB with CONTAINER TransactionManagementType means that every method is transactional and by default using REQUIRED TransactionAttributeType. You may even skip the TransactionManagement annotation, since CONTAINER TransactionManagementType is enabled by default for EJBs. You may use the TransactionAttribute annotation to override the default.
You may use the TransactionAttribute annotation either on class or method level or both, in which case method annotation will override class annotation for the specific method.

Disable Transaction for specific method

I'm using a Interface with #Transaction, and I have a method that performs a loop and check some information, but this loop takes long time to finish it, and i added a parameter in the database. And inside of the loop, is checked the parameter, and if is equal true, the loop will stop.
My problem is at the moment that check the parameter, it not get the parameter updated, it keep with the old value of the parameter.
is there a way to keep the transaction on interface and disable for specific method?
Try to split in two your method and you put "Requires new" on that check the parameters, in order to create a new transaction and suspend the current transaction if one exists.
#Transactional(propagation = Propagation.REQUIRES_NEW)
I hope I've given you all the answers about your question.
The first thing is undestand why you are using #Transaction on interfaces, beacause the correct way is to annote concrete classes (and methods of concrete classes) with the #Transactional annotation.
From spring references documentation:
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.
Then can you share your code with us?

Categories