I have a set of classes I would like to require a certain method implemented with Spring's #Scheduled annotation. I don't want a default defined, I just want to require that the annotation is used on a certain method.
Is this possible either through Interfaces or abstract classes?
Related
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.
For one of my requirment i have created a inteface with multiple methods and each method annotated with my own java custom annotation.
I have a spring aop aspect for my implementation class and i am not able to get my custom annotation in aop aspect.
after doing debug i understood my custom annotation is part of the interface and not in implementation class.
How can i get my custom annotation in my implementation methods which declared in interface ?
In Java, annotations are not inhereted from interfaces.With aspects you must annotate the implementation class (and/or methods within that class), not the interface (if any) that the class implements. String aop follows Java’s rule that annotations on interfaces are not inherited.
So, if you want to work with your annotation , create an abstract super class to be able to do this.
Inside aspect you work with proxy object and methods are wrapped in proxy calls. But if you know a real class/interface , you can get annotation by reflection api from source class/interface
I have a usecase where i want a particular class or a spring bean to be injected in a set of classes that have a particular annotation. Basically i want a few set of methods to be added to the annotated classes.
Suppose i have a class annotated with annotation #Finders. Then i want the class to be able to use some predefined methods like
findById(), findByName() etc to be available to the class and we should be able to call these functions in a static context like
User.findById() and so on.
Is there a way to inject these methods to the class using Java or Spring. Can i use reflection to do this.
Is there any other way i can get this done in java.
Spring doc has the two recommendations:
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.
(from http://static.springsource.org/spring/docs/3.0.x/reference/transaction.html)
and
Spring AOP uses either JDK dynamic proxies or CGLIB to create the
proxy for a given target object. (JDK dynamic proxies are preferred
whenever you have a choice).
(from http://static.springsource.org/spring/docs/3.0.x/reference/aop.html#aop-understanding-aop-proxies)
Do I understand correctly that in order to follow both recommendations, I need to have #Transactional annotation on concrete class, but still provide an interfaces (that this class implements) containing all transactional methods, so that Spring can use JDK dynamix proxies for this interface?
It works like this
Have a business interface with methods, do not annotate interface methods with #Transactional
Write an implementation class for interface defined above and annotate methods in impl class with #Transactional
As spring recommends usage of JDK dynamic proxies which are interface based hence we need to have business interface in place.
Also, as stated
Java annotations are not inherited from interfaces
We need to annotate concrete / implementation class methods with #Transactional
I have a number of abstract superclasses from which my concrete class inherit various methods. Some of these methods need to have JPA or JAXB annotations placed on them in the concrete class. Currently I do this via the following:
#MyLocalAnnotations
#Override
public method inheritedMethodHere (yadda yadda)
{
super.inheritedMethodHere(yadda yadda);
}
Is there a way to do this without overriding the method? It seems like such a waste to override a method only to supply local annotations.
Unfortunately, there isn't a better way than what you are doing now. To do what you are describing you will have to override the method, considering that your JPA annotation will need information specific to the concrete class.
With JPA annotations, you actually have two options -- you can annotate the methods, or you can annotate the properties. On our project we've standardized on annotating properties rather than methods, but this won't help you either, as the properties are presumably part of the concrete class. (If they are somehow shared in the super-class, then you REALLY will need to annotate the methods, and override them).
Its hard to make a recommendation without seeing your schema, but if your entity classes have so much in common that they share many properties in the super-class -- might they simply be stored in the same table, perhaps with a differentiating type column?
Or alternatively if they are not nearly identical, might you just reproduce the common properties in each concrete class? You might be causing yourself more work rather than saving yourself by trying to capture the common properties in the super class. Since you will have to annotate them individually in the concrete classes, just declare them in the concrete classes. If you need common methods that interact with these properties, a separate Utility class to capture those functions could be the answer.
On our project we DO sometimes use a common super class for entities, but it captures some meta-data about the entity -- nothing that would impact persistence logic. Therefore, no JPA annotations are needed (nor would they make sense) in the abstract class.