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.