uppose ther is a class A :
public class A {
public B b;
public void justDoIt1(){
b.getB();
}
#SomeAnnotation
public void justDoIt2(){
b.getB();
}
}
and class B:
public class B{
public void getB(){
System.out.println("get");
}
}
How do we create pointcut to execution of B.getB() that is called from within a method annotated with #SomeAnnotation?
Here is what I've tried
#Aspect
public class LocalizationAspect {
#Before(value = "#within(Localize) && execution(* B.getB())")
public void aspectStuff() {
System.out.println("aspect");
}
}
just to make my point clear : expected output will be when calling justDoIt2();
aspect
get
but when calling justDoIt1();
get
Note: i'm using SpringAOP (maybe it has some restrictions on this)
Any help on this?
If I were using plain AspectJ I would do this:
execution(* B.getB()) && cflow(#withincode(SomeAnnotation))
"execution of getB() in the control flow of a method annotated with SomeAnnotation. But this does mean it will get caught if deeper in the flow, which may not be what you want. e.g. if the method annotated with SomeAnnotation calls something which calls something else which then calls getB() - that will get caught by this advice.
I don't know how it'll behave under Spring AOP though.
EDIT: On further thinking, the pointcut above is perhaps not optimal as #withincode() might create more byte code than absolutely necessary. A more optimal version is probably:
execution(* B.getB()) && cflow(execution(#SomeAnnotation * *(..)))
#withincode(SomeAnnotation) will advise all join points within a method marked #SomeAnnotation, but you are probably only interested in the execution join point.
Related
I want to have annotation on class level that will execute advice on every method in annotated class.
Is that even possible.
Example: I would like to annotate OmniDemoService with #DoSomethingForMe and I want both method1 and method2 to log "look at me" before execution
This example is not working and I don't know why. When I transform Pointcut to Around and just use it with annotation (also change annotation ElementType to method) everything is working on method level.
So I think it is wrong defined Pointcut.
Annotation:
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
public #interface DoSomethingForMe {
}
Advice:
#Aspect
#Component
public class DoSomethingForMeAdvice {
private static final Logger logger = LoggerFactory.getLogger(DoSomethingForMeAdvice.class);
#Pointcut("execution(public * *(..)) && #annotation(DoSomethingForMe)")
public void anyAnnotatedMethod() {
}
#Before("anyAnnotatedMethod()")
public void acquireExecution() {
logger.info("look at me");
}
}
Usage:
#Service
#DoSomethingForMe
public class OmniDemoService {
private static final Logger logger = LoggerFactory.getLogger(OmniDemoService.class);
public void method1() {
logger.info("---1---");
}
public void method2() {
logger.info("---2---");
}
}
Your issue is that you are confusing pointcut definition with advices.
Pointcut is aiming, advice performs the actual WhateverYouWantToBeExecuted. Like for example
#Pointcut("#annotation(com.omnidemo.advice.DoSomethingForMe)")
public void anyAnnotatedMethod() {
}
#Before("anyAnnotatedMethod()")
public void logMethodCall(JoinPoint jp) {
String methodName = jp.getSignature().toShortString();
logger.info("Executing: " + methodName);
}
Solution for the problem is to use within for pointcut
#Pointcut("#within(DoSomethingForMe)")
public void anyAnnotatedMethod() {
}
#Before("anyAnnotatedMethod()")
public void acquireExecution() {
logger.info("look at me");
}
Solution provided by #J Asgarov in the comments
Check out what the AspectJ quick reference says about #annotation():
any join point where the subject has an annotation of type
SomeAnnotation
You used #annotation(DoSomethingForMe) but the "subject" of a method execution is a method. So that would mean any method annotated #DoSomethingForMe.
Use #this(DoSomethingForMe) or #target(DoSomethingForMe).
Thanks to kriegaex for pointing out that #this and #target must be evaluated at runtime, which would pollute the codebase a lot (i.e. check in every method). So the next approach is better:
If you check the AspectJ manual section about type patterns you will see that you can annotate the type directly. Please also remember to use use fully qualified class names. So that would be:
execution(public * (#com.path.DoSomethingForMe *).*(..))
Also, if you have such a simple pointcut and you don't need to reuse it, I think you can drop the additional method and just use it in the advice directly:
#Before("execution(public * (#com.path.DoSomethingForMe *).*(..))")
which says: "before the execution of any public method of a type annotated with #com.path.DoSomethingForMe", where "before the execution of a method" means "inside the method, at the beginning".
Alternatively, if this pointcut looks a bit too complicated for you, you can separate annotation matching and method matching like this, as suggested by J Asgarov in his comment:
#Before("execution(public * *(..)) && #within(com.path.DoSomethingForMe)")
Below is my code snippet:
ServiceImpl.java
#Service
public class ServiceImpl implements Service {
private Response worker(Audit send) throws ArgumentException {
System.out.println("STEP_1");
worker(send.getRequest(), send.getId());
}
private Response worker(Request request, String id) throws ArgumentException {
System.out.println("STEP_2");
try {
//throwing some exception
} catch (Exception e) {
System.out.println("STEP_3");
}
}
}
Now, what I want is whenever NullPointerException is being thrown from method worker(Request request, String id) as shown above I want to perform some specific task. For that I have written an Aspect class which is following:
MyAspect.java
#Aspect
#Component
public class MyAspect{
#Pointcut("com.xyz.myapp.ServiceImpl.worker() && args(request,..)")
private void someOperation(Request request) {}
#Before("someOperation(request)")
public void process(Request request) {
System.out.println("SUCCESS");
}
#AfterThrowing("com.xyz.myapp.ServiceImpl.worker() && args(request,..)")
public void doRecoveryActions() {
System.out.println("EXCEPTION_SUCCESS");
}
}
Current Output:
STEP_1
STEP_2
STEP_3
Desired Output:
STEP_1
STEP_2
STEP_3
SUCCESS
EXCEPTION_SUCCESS
As you can see MyAspect.java is not getting triggered hence NOT printing values.
What can be the reason for this?
Note:
I tried making worker as public classes too but it didn't work.
Also tried changing the name of the methods to eliminate any overloading issue that too didn't work.
Tried various other pointcut expressions all in vain as of now.
In my application there are other aspect classes working absolutely fine.
You made a typical Spring AOP beginner's mistake: You assume that it works for private methods, but as the documentation clearly says, it does not. Spring AOP is based on dynamic proxies, and those only work for public methods when implementing interfaces via JDK proxies and additionally for protected and package-scoped methods when using CGLIB proxies.
You should make the worker() method public if you want to intercept it from an aspect.
P.S.: Full-fledged AspectJ also works for private methods, but to switch to another AOP framework would be overkill here.
Update: You also have other problems in your code:
The first worker method, even if you make it public, does not return anything. The last statement should be return worker(send.getRequest(), send.getId());, not just worker(send.getRequest(), send.getId());.
Your pointcut com.xyz.myapp.ServiceImpl.worker() will never match because it has an empty argument list, but your method has arguments. The args() does not help you here.
The syntax of your pointcut is also wrong because it does not specify a return type for the method, not even *. Furthermore, the method name itself is not enough, it should be enclosed in an actual pointcut type such as execution(). I.e. you want to write something like:
#Pointcut("execution(* com.xyz.myapp.ServiceImpl.worker(..)) && args(request, ..)")
private void someOperation(Request request) {}
To intercept a method that throws an exception you can use this code (works only if methods are public):
#AfterThrowing(pointcut="com.xyz.myapp.SystemArchitecture.dataAccessOperation()",throwing="ex")
public void doRecoveryActions(NullPointerException ex) {
// ...
}
Source: Spring AOP
I am trying to learn AspectJ and figuring out how to retrieve specific joinpoints at certain points in a flow. My example is something like this:
I want to run an unit test annotated with JUnit's #Test then any methods called in that test that may be in another class annotated with another annotation, let's say #Example, then I could access basically the entire flow at those certain points so I had the ability to get the class name/method name of the test annotated with #Test and then also get the method information for the method annotated #Example. I've included some example code for clarification:
Test class:
public class ExampleTest {
#Test
public void shouldTestSomething() {
ExampleClass exampleClazz = new ExampleClass();
exampleClazz.something();
// ...
}
POJO:
public class ExampleClass {
#Example
public void something() {
// do something
end
end
So with these classes, I would like to make an aspect that would basically find any kind of #Example called within a #Test so I can then have access to both (or more) join points where I can grab the method/class signatures from the AspectJ JoinPoint object.
I tried something like this:
#Aspect
public class ExampleAspect {
#Pointcut("execution(#org.junit.Test * *(..))
&& !within(ExampleAspect)")
public void testPointCut() {}
#Pointcut("#annotation(com.example.Example)")
public void examplePointCut() {}
#After("cflow(testPointCut) && examplePointCut()")
public void doSomething(JoinPoint joinPoint) {
System.out.println(joinPoint.getSignature());
}
}
But the output looks like this:
void ExampleTest.ExampleClass.something()
The main issue is that it is missing the name of the test method (shouldTestSomething()) in the signature. What would be the best way to retrieve that?
Not sure if I understand correctly, but if you need to access information about the context from where a piece of code under a join point of your interest gets called, then what you need is the thisEnclosingJoinPointStaticPart (in native AspectJ syntax). If you are using AspectJ 5 annotation style aspects, just add a parameter to your advice method with the type JoinPoint.EnclosingStaticPart.
Note that this is not available for execution() style pointcuts, only for call() style pointcuts, otherwise the JoinPoint.EnclosingStaticPart and JoinPoint.StaticPart will be the same.
This means you need to rewrite your aspect in the following way:
#Aspect
public class ExampleAspect {
#Pointcut("execution(#org.junit.Test * *(..)) && !within(ExampleAspect)")
public void testPointCut() {
}
#Pointcut("call(#com.example.Example * *(..))")
public void examplePointCut() {
}
#After("cflow(testPointCut()) && examplePointCut()")
public void doSomething(JoinPoint joinPoint, EnclosingStaticPart enclosingStaticPart) {
System.out.println(joinPoint.getSignature() + " was invoked from "
+ enclosingStaticPart.getSignature());
}
}
The output with your test code would be:
void q35991663.com.example.ExampleClass.something() was invoked from void q35991663.com.example.ExampleTest.shouldTestSomething()
I also rewrote your examplePointCut. The pointcut expression #annotation(com.example.Example) would mean
any join point where the subject has an annotation of type com.example.Example
which would include both execution() and call() type join points. We need only the call() join points in this case, so #annotation() isn't even necessary if you are not planning to bind the value of the annotation to the advice context.
Classes use compile time weaving.
Imagine I have the aspect class:
#Aspect
public class SecurityInterceptor {
#Pointcut("within(#org.springframework.stereotype.Controller *)")
public void beanAnnotatedWithController() {}
#Pointcut("execution(public * *(..)) && args(*,httpReq)")
public void publicMethods(HttpServletRequest httpReq) {}
#Pointcut("beanAnnotatedWithController() && publicMethods(httpReq)")
public void controllerMethods(HttpServletRequest httpReq) {}
#Pointcut("execution(public * *(..)) && args(httpReq)")
public void publicMethodsRequestOnly(HttpServletRequest httpReq) {}
#Pointcut("beanAnnotatedWithController() && publicMethodsRequestOnly(httpReq)")
public void controllerMethodsOneArg(HttpServletRequest httpReq) {}
#Around(value = "controllerMethods(httpReq)")
public Object populateSecurityContext(final ProceedingJoinPoint joinPoint, HttpServletRequest httpReq) throws Throwable {
return popSecContext(joinPoint, httpReq);
}
#Around(value = "controllerMethodsOneArg(httpReq)")
public Object populateSecurityContextOneArg(final ProceedingJoinPoint joinPoint, HttpServletRequest httpReq) throws Throwable {
return popSecContext(joinPoint, httpReq);
}
}
What is the correct way to use #DeclarePrecedence to determine the execution order?
Please read paragraph "Advice precedence" in the language semantics section of the AspectJ documentation.
Precedence of aspects can be declared explicitly, precedence of advice within a single aspect is determined by rules described in the document and cannot be changed, AFAIK. So #DeclarePrecedence will not help you in this case, only changing the order of advice within the aspect file.
If you're are looking for the the order of multiple aspects, you can create an aspect like:
#Aspect
#DeclarePrecedence("AuthorizationAspect, MySpecialAspect, LastAspect")
public class CoordinationAspect {
// empty
}
This will indeed work over multiple aspects. Inside a single aspect is another matter and can not be changed AFAIK, but I don't see why this would be an issue.
When two pieces of advice defined in the same aspect both need to run at the same join point, the ordering is undefined (since there is no way to retrieve the declaration order via reflection for javac-compiled classes). Consider collapsing such advice methods into one advice method per joinpoint in each aspect class, or refactor the pieces of advice into separate aspect classes - which can be ordered at the aspect level.
from Spring AOP documentation here (section 6.2.4.7. Advice ordering) https://docs.spring.io/spring/docs/2.0.x/reference/aop.html
If it helps in case you came looking for this here.
I'm trying to imitate Spring's AspectJ #Async support but with a message bus.
The issue is I need to know if my Message Bus (RabbitMQ MessageListener) is calling the method or a normal (all others) caller where the method will return instantly.
My annotation is called #MQAsync instead of Springs #Async.
package com.snaphop.mqueue;
import org.apache.log4j.Logger;
import com.snaphop.mqueue.MQAsync;
public aspect MQAsyncAspect {
//pointcut asyncTypeMarkedMethod() : execution(#MQAsync void *(..));
pointcut asyncTypeMarkedMethod() : call(#MQAsync void *(..));
private static final Logger log = Logger.getLogger("MQAsync");
Object around() : asyncTypeMarkedMethod() {
if (listenerIsCaller) {
return proceed();
}
//Send the method parameters to the message bus.
//this logic isn't here for brevity.
return null;
}
}
The call pointcut will get me the caller context but that will not work as I will be calling the method with my message listener through reflection. The execution pointcut (commented out) will not tell me who is calling the method.
Is there a way to determine the caller class maybe through some sort of stack dump analysis?
Actually cheeken's answer is nice, but for AspectJ call() pointcuts you can get the calling class much more easily and without ugly reflection:
thisEnclosingJoinPointStaticPart.getSignature().getDeclaringType()
Please consider to accept this answer if you think it is better than the other one, otherwise just enjoy the power of AspectJ. ;-)
You can determine which class is invoking the current method with the following call. Note that you'll have to catch ClassNotFoundException (unless you're satisfied simply retrieving the name as a String).
Class.forName(Thread.currentThread().getStackTrace()[2].getClassName());
Why the third element? Because the stack is ordered like so when the stack trace method is invoked:
Thread#getStackTrace()
CurrentClass.currentMethod()
ParentClass.parentMethod()
This is an alternative that seems more light since is native and commonly used by the SecurityManager. To use it we need a utility class because the the method we need is protected.
public class CallStackUtils extends SecurityManager {
static CallStackUtils sm = new CallStackUtils();
public Class[] getCallersClassesStack0() {
return getClassContext();
}
static public Class[] getCallersClassesStack() {
return sm.getCallersClassesStack0();
}
}