I am trying to add some pre-processing logic using AspectJ in my Spring MVC project. I have a #Before method and the corresponding PointCut in place. However, this method is not getting invoked at all when I invoke any of the methods matching the PointCut.
Here are my classes:
#Aspect
#Configuration
public class ConcurrencyAspectConfig {
#Before("execution(public * com.test.wms.service.dto.PackingDtoApi.*(..))")
public void adviceMethod(JoinPoint joinPoint) {
System.out.println("**** ASPECT START");
}
}
#EnableAspectJAutoProxy
#Configuration
#ComponentScan({SpringConstants.PACKAGE_SPRING})
public class AppConfig {
}
When executing any of the public methods in PackingDtoApi, I am expecting to see the **** ASPECT START message on the console. However, it seems that the Advice method never gets invoked. What could be the reason?
There could be mainly two reasons for your implementation to not work:
Wrong Pointcut expression - Double check your pointcut expression
PackingDtoApi is not a spring bean - Annotate the class with a stereotype annotation like #Component
Note: If this doesn't solve your issue, please share the code for
PackingDtoApi class
Related
The idea is to create annotations hierarchy (similar to #Service, #Component etc) using #AliasFor annotation. This should give me the possibility to define aspect, that would execute on parent annotation, and every alias of it. But somehow it doesn't work for me.
#ComponentScan is fine, #EnableAspectJAutoProxy is set.
Example:
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.TYPE, ElementType.METHOD})
public #interface ParentAnnotation {
}
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
#ParentAnnotation
public #interface ChildAnnotation {
#AliasFor(annotation = ParentAnnotation.class)
String value() default "";
}
#Aspect
#Component
public class EventRecorderAspect {
#Around("#annotation(com.example.ParentAnnotation)")
public void exampleMethod(ProceedingJoinPoint joinPoint) throws Throwable {
// This should be executed for both #ParentAnnotation and #ChildAnnotation
}
}
#RestController
public class ExampleController {
#ChildAnnotation // This should result in executing aspect for every implementation
String controllerMethod();
}
UPDATE:
I've updated code, as #M.Deinum suggested in a comment below. But it still doesnt work.
AspectJ pointcut matching syntax, a subset of which is used by Spring AOP, is ignorant of meta annotations, even though withing the Spring framework as such there is support for it in other places. I think the closest you can get to specifying meta annotations in your pointcut is to do it explicitly up to the nesting level you require. See this answer for examples showing the syntax variants for both
class-level, e.g. within(#(#com.example.ParentAnnotation *) *),
method-level, e.g. execution(#(#com.example.ParentAnnotation *) * *(..))
annotations.
Update: #Ariel Grabijas asked in a follow-up comment:
So is there a way to somehow inherit annotations from interface method to class method?
Not in Java and also not by means of Spring AOP. But there is a workaround using native AspectJ inter-type definitions (ITD).
Let's take an example of a simple Spring Boot program:
Application.java
#SpringBootApplication
#EnableScheduling
public class Application {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class);
}
}
SuperClass.java
public abstract class SuperClass {
#Scheduled(fixedRate = 5000)
public void printSomething() {
System.out.println("this is the super method");
}
}
SubClass.java
#Component
public class SubClass extends SuperClass {
}
According to this answer, only annotations annotated by #Inherited are inherited by subclasses, and #Scheduled does not have such an annotation. So how come this is working?
#Inherited only applies to class types, not methods.
Note that this meta-annotation type has no effect if the annotated
type is used to annotate anything other than a class. Note also that
this meta-annotation only causes annotations to be inherited from
superclasses; annotations on implemented interfaces have no effect.
When Spring scans beans for the #Scheduled annotation (or others), it looks for all methods in the bean class. SubClass has a printSomething so Spring decides it can enhance it with the scheduling behavior.
Spring handles #Scheduled a little differently than the standard proxying mechanism and is able to invoke private methods annotated with it.
Had you overriden the printSomething method in the subclass and omitted the #Scheduled annotation on that declaration, Spring would not have applied the scheduling behavior.
I have a Spring AOP aspect used for logging, where a method can be included for logging by adding an annotation to it, like this:
#AspectLogging("do something")
public void doSomething() {
...
}
I've been using this on Spring beans and it's been working just fine. Now, I wanted to use it on a REST-service, but I ran into some problems. So, I have:
#Path("/path")
#Service
public class MyRestService {
#Inject
private Something something;
#GET
#AspectLogging("get some stuff")
public Response getSomeStuff() {
...
}
}
and this setup works just fine. The Rest-service that I'm trying to add the logging to now has an interface, and somehow that messes stuff up. As soon as I add the #AspectLogging annotation to one of the methods, no dependencies are injected in the bean, and also, the aspect is newer called!
I've tried adding an interface to the REST-service that works, and it gets the same error.
How can having an interface lead to this type of problems? The aspect-logger works on classes with interfaces elsewhere, seems it's only a problem when it's a REST-service..
Ref the below Spring documentation (para 2) -
To enable AspectJ annotation support in the Spring IoC container, you
only have to define an empty XML element aop:aspectj-autoproxy in your
bean configuration file. Then, Spring will automatically create
proxies for any of your beans that are matched by your AspectJ
aspects.
For cases in which interfaces are not available or not used in an
application’s design, it’s possible to create proxies by relying on
CGLIB. To enable CGLIB, you need to set the attribute
proxy-targetclass= true in aop:aspectj-autoproxy.
In case your class implements an interface, a JDK dynamic proxy will be used. However if your class does not implement any interfaces then a CGLIB proxy will be created. You can achieve this #EnableAspectJAutoProxy. Here is the sample
#Configuration
#EnableAspectJAutoProxy
public class AppConfig {
#Bean
public LoggingAspect logingAspect(){
return new LoggingAspect();
}
}
#Component
#Aspect
public class LoggingAspect {
...
...
}
In my opinion what you are actually trying to do is to add spring annotations to a class maintained by jersey. In the result you are receiving a proxy of proxy of proxy of somethng. I do not think so this is a good idea and this will work without any problems. I had a similar issue when I tried to implement bean based validation. For some reasons when there were #PahtParam and #Valid annotations in the same place validation annotations were not visible. My advice is to move your logging to a #Service layer instead of #Controller.
I want to run some code before every method in a Spring (3.2.3) #Controller. I have the following defined but it won't run. I suspect the pointcut expression is incorrect.
dispatcher-servlet.xml
<aop:aspectj-autoproxy/>
<bean class="com.example.web.controllers.ThingAspect"/>
c.e.w.c.ThingAspect
#Pointcut("execution(com.example.web.controllers.ThingController.*(..))")
public void thing() {
}
#Before("thing()")
public void doStuffBeforeThing(JoinPoint joinPoint) {
// do stuff here
}
Your pointcut expression is missing a return type like void, String or *, e.g.
execution(* com.example.web.controllers.ThingController.*(..))
The correct way to do it in current versions of Spring MVC is through a ControllerAdvice.
See: Advising controllers with the #ControllerAdvice annotation
For previous versions, refer to this answer of mine:
https://stackoverflow.com/a/5866960/342852
Besides #ControllerAdvice that is already mentioned in another answer, you should check out Spring MVC interceptors.
They basically simplify AOP for controllers and can be used in cases where #ControllerAdvice doesn't give you enough power.
Main References for My Question:
Writing Method Interceptors for Google Guice: http://code.google.com/p/google-guice/wiki/AOP
The JavaDoc for the MethodInterceptor interface: http://aopalliance.sourceforge.net/doc/org/aopalliance/intercept/MethodInterceptor.html
General references about Java annotations: http://docs.oracle.com/javase/tutorial/java/javaOO/annotations.html and http://docs.oracle.com/javase/1.5.0/docs/guide/language/annotations.html
Now My Question:
I am writing a Java application that heavily relies on Google Guice for creating objects and handling dependency injection. I am trying to use interceptors to run pre-processing code before certain annotated methods are executed. So far, I have successfully been able to execute interceptors (using the MethodInterceptor interface) on methods that have been annotated, using Guice's instructions. However, I want to now write interceptors that will execure on Parameter Annotations.
Here is an example scenario. First, I create my own annotation. For example::
#BindingAnnotation
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.PARAMETER)
public #interface MyParameterAnnotation {
}
Next, I write my own interceptor for this annotation:
public class MyParameterAnnotationInterceptor implements MethodInterceptor {
#Override
public Object invoke(MethodInvocation invocation) throws Throwable {
// Do some stuff
return invocation.proceed();
}
}
Here's an example of how I intend on using #MyParameterAnnotation:
public class ExampleObject {
public String foo(#MyParameterAnnotation String param) {
...
}
}
Finally, I need to create a Guice Injector and use it to create an instalce of ExampleObject, or else I cannot use a method interceptor in this project. I configure the Injector so that the MyParameterAnnotationInterceptor is bound to #MyParameterAnnotation, like so:
final MethodInterceptor interceptor = new MyParameterAnnotationInterceptor();
requestStaticInjection(MyParameterAnnotationInterceptor.class);
bindInterceptor(Matchers.any(), Matchers.annotatedWith(MyParameterAnnotation.class), interceptor);
When I follow the above steps and execute a call to ExampleObject.foo(), unfortunately the interceptor is not executed despite the parameter being marked by #MyParameterAnnotation. Note that these similar steps will work if the annotation was placed at the method level instead.
This leads me to come up with two possible conclusions: either Guice cannot support binding an interceptor to a parameter annotation, or I am doing something completely incorrect (perhaps I should use another AOP Alliance interface for the interceptor, like FieldInterceptor, but I highly doubt it because the JavaDoc for Guice's AbstractModule suggests that the bindInterceptor() method can only use a MethodInterceptor parameter).
Nonetheless, all help us much appreciated :)
The matcher is for method annotations not method parameter annotations.
There is no matcher provided by Guice for method parameter annotations--you either have to write one yourself or use some other scheme. Note that this is a bit of an odd use case--Generally you can get away with
public class ExampleObject {
#MyAnnotation
public String foo(String param) {
...
}
}
You have the right Guice interceptor config for the above example.