Aspect execution not firing on method - java

I am kinda new to Aspects and I am trying to surround a function with an aspect but I can't get it called.
The method signature is as follows:
public <T> T get(String uri, List<BasicNameValuePair> nameValuePairs, final Class<T> clazz)
and it's defined in class with fully-qualified name:
com.X.Y.infrastructure.rest.RestClient
And the Aspect
#Aspect
public class WebRequestTimeLoggerAspect {
#Around("execution(* com.X.Y.infrastructure.rest.RestClient.get(..))")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("hijacked method : " + joinPoint.getSignature().getName());
System.out.println("hijacked arguments : " + Arrays.toString(joinPoint.getArgs()));
System.out.println("Around before is running!");
Object ret = joinPoint.proceed();
System.out.println("Around after is running!");
return ret;
}
}
I just cant seem to find the problem.
Everything is declared and spring loads both beans into the container.
If possible. How do I add another function to the same execute deceleration?
Thanks.
Update:
So I have managed to do some progress, apparently I needed to Change project configuration to support Aspectj (in eclipse) but now I am getting the following error:
applying to join point that doesn't return void: method-execution(java.lang.Object com.X.Y.infrastructure.rest.RestClient.get(java.lang.String, java.util.List, java.lang.Class))
I will assume that i need to specify the return argument. I thought * will catch all, but that seems to be for void.
So how does the point cut should look for generics like that?
Thanks again
Another update
Following the comment I have added a return value to the method. But the aspect is still not firing.
By request the spring configuration:
<aop:aspectj-autoproxy />
<bean id="webRequestTimeLoggerAspect" class="com.X.Y.infrastructure.rest.WebRequestTimeLoggerAspect" />
And in fact I don't believe I need to declare a bean for that aspect because I have package scan. But just in case.

Related

Spring AOP custom annotation, getting Null with annotation arguments

I am using this custom annotation for logging execution time, annotation could be present on method or class in which all public methods have it. Everything works fine, except in case of method level "LogExecutionTime logExecutionTime" comes null. This throws an NPE.
#Around("#annotation(logExecutionTime) || #within(logExecutionTime)")
public Object logExecutionTime(ProceedingJoinPoint joinPoint, LogExecutionTime logExecutionTime) throws Throwable {
final Logger logger = LoggerFactory.getLogger(joinPoint.getTarget().getClass());
final String name = joinPoint.toShortString();
final StopWatch stopWatch = new StopWatch(name);
stopWatch.start(name);
try {
return joinPoint.proceed();
} finally {
stopWatch.stop();
if (logExecutionTime.value()) {
logger.info(joinPoint.getSignature().getName() + ".time=", stopWatch.getTotalTimeSeconds());
}
}
}
if I reverse the order-
#Around("#within(logExecutionTime) || #annotation(logExecutionTime)")
the behavior reverses and I get a valid object at method level and null at class level annotated methods.
I have worked around this by having 2 explicit methods and separating the two-
#Around("#within(logExecutionTime)")
public Object logExecutionTimeClassLevel(ProceedingJoinPoint joinPoint, LogExecutionTime logExecutionTime) throws Throwable {
return logExecutionTimeMethodLevel(joinPoint, logExecutionTime);
}
#Around("#annotation(logExecutionTime)")
public Object logExecutionTimeMethodLevel(ProceedingJoinPoint joinPoint, LogExecutionTime logExecutionTime) throws Throwable {
final Logger logger = LoggerFactory.getLogger(joinPoint.getTarget().getClass());
final String name = joinPoint.toShortString();
final StopWatch stopWatch = new StopWatch(name);
stopWatch.start(name);
try {
return joinPoint.proceed();
} finally {
stopWatch.stop();
if (logExecutionTime.value()) {
logger.info(joinPoint.getSignature().getName() + ".time=", stopWatch.getTotalTimeMillis());
}
}
Was hoping to understand this behavior, when we use OR '||' with two pointcuts.
class level
#LogExecutionTime
#Component
public class CleanUpService implements ICleanUpService { ... }
method level
#Scheduled(fixedDelay = 100)
#LogExecutionTime(false)
public void processMessageQueue() { ... }
I came to run you example, and reproduce the same example as yours, when it come to runtime expression is same weird because when you specify the annotation on class level and you write this expression
#Around(" #within(logExecutionTime) || #annotation(logExecutionTime) ")
The point cut will evaluate to true for you class (event you annotation its available in joinPoint.getTarget().getClass().getAnnotations(), )
Now when it come to binding the variable the compiler check all your expressions that mean binding #within(logExecutionTime) to variable logExecutionTime and #annotation(logExecutionTime) to the same variable , if the method is not annotated it will ge null, => override the initial with, that cause all senarios you mention.
Try to put this expression #within(logExecutionTime) || #annotation(logExecutionTime) || #within(logExecutionTime)
and you'll get you variable not null which prove what i said, last #within(logExecutionTime) override what precedent
The key here is that the logic applied to select the point cut matching not the same when it come context-binding
Now when it come to AOP point-cut you must be careful and follow best practice as the spring team they mention here to avoid weird runtime results
Cheers
This cannot work, it does not even compile with the AspectJ compiler. Maybe in your IDE and with Spring AOP you do not see any warnings or errors, but I see:
ambiguous binding of parameter(s) logExecutionTime across '||' in pointcut
This means that it is not clear which annotation should be selected if e.g. both the class and the method contain an instance of that annotation. It is, as the error message said, ambiguous. But ambiguous parameter bindings across || are not permitted. They can also happen if you try to bind values from different "or" branches to a single parameter in an args() list.
I had the same problem. What you want is exactly same as Spring #Transcriptional behaves (I mean, class level or method level annotation with parameters). I used your solution but to get the class level parameter value (as the annotation object received null), I used reflection. I know it is a dirty solution! But I tried other solutions and couldn't find!
Her is the full code. This will call the advice code either the annotation is used on a class or a method. If the annotation is placed on both (class and method), the method takes the precedence.
#Aspect
#Configurable
#Component
public class DynamicValueAspect {
#Around(" #within(dynamicValueAnnotation) || #annotation(dynamicValueAnnotation))")
public Object process(ProceedingJoinPoint joinPoint, DynamicValue dynamicValueAnnotation) throws Throwable {
String annotationParameter;
if (dynamicValueAnnotation == null) { //class level annotation
annotationParameter = extractClassLevelAnnotationParameterValue(joinPoint);
} else {
annotationParameter = dynamicValueAnnotation.myAnnotationParameter();
}
System.out.println(" " + annotationParameter);//get the annotation parameter value
return joinPoint.proceed();
}
private String extractClassLevelAnnotationParameterValue(ProceedingJoinPoint joinPoint) {
Annotation[] classAnnotations = joinPoint.getTarget().getClass().getAnnotations();
for (Annotation annotation : classAnnotations) {
if (annotation.annotationType() == DynamicValue.class) {
return ((DynamicValue) annotation).myAnnotationParameter();
}
}
throw new RuntimeException("No DynamicValue value annotation was found");
}
}
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD, ElementType.TYPE})
public #interface DynamicValue {
String myAnnotationParameter();
}
Let's know if you got a cleaner solution!
The problem with your workaround appears when you annotate both a class and a method with the annotation, resulting in triggering both of them.
To prevent it declare the class level advice as:
#Around("!#annotation(LogExecutionTime) && #within(logExecutionTime)")

How to create custom java annotation to log method parameters

I am writting JavaEE application and I would like to use and create custom annotation, which will log data, when annotated method will be called. All I would like to do is, that when annotated method is called, code iterate through all passed method parameters and writes to standard output parameter keys and values.
Some example:
public class Test {
#LogMethodData
public int sum(int first, int second) {
return first + second;
}
}
I would like to achieve, that when a custom metod will be annotated with #LogMethodData, that code behind will take care and log passed method parameters to standard output (something like "Method data: first - 4, second - 5" if parameter first contains value 4 and parameter second contains value 5), independent from number of passed parameters to methods.
I would be very happy if someone could help me with that, because I have been already searching for a solution, but I didn't found anything usefull. And last, I am not familiar with this things.
Regards,
Dahakka
There is no need to define your own Annotation, you can use the #Interceptors Annotation in the EE Container as explained here.
#Interceptors(LoggingInterceptor.class)
Within the Interceptor you'll get a Context that contains your Parameters
public class LoggingInterceptor {
...
#AroundInvoke
public Object modifyGreeting(InvocationContext ctx) throws Exception {
....
Object[] parameters = ctx.getParameters();
try {
return ctx.proceed();
} catch (Exception e) {
logger.warning("Error calling ctx.proceed in modifyGreeting()");
return null;
}
}
}
another example : here

Joinpoint VS ProceedingJoinPoint in AOP using aspectJ?

Can any one tell me what is the difference between Joinpoint and Proceedingjoinpoint?
When to use Joinpoint and Proceedingjoinpoint in the method of aspect class?
I used the JoinPoint in my AspectJ class like:
#Pointcut("execution(* com.pointel.aop.test1.AopTest.beforeAspect(..))")
public void adviceChild(){}
#Before("adviceChild()")
public void beforeAdvicing(JoinPoint joinPoint /*,ProceedingJoinPoint pjp - used refer book marks of AOP*/){
//Used to get the parameters of the method !
Object[] arguments = joinPoint.getArgs();
for (Object object : arguments) {
System.out.println("List of parameters : " + object);
}
System.out.println("Method name : " + joinPoint.getSignature().getName());
log.info("beforeAdvicing...........****************...........");
log.info("Method name : " + joinPoint.getSignature().getName());
System.out.println("************************");
}
But what I see in other resources is:
#Around("execution(* com.mumz.test.spring.aop.BookShelf.addBook(..))")
public void aroundAddAdvice(ProceedingJoinPoint pjp){
Object[] arguments = pjp.getArgs();
for (Object object : arguments) {
System.out.println("Book being added is : " + object);
}
try {
pjp.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
}
Here what will ProceedingJoinPoint do differently compare to 'JointPoint? Also what willpjp.proceed()` do for us?
An around advice is a special advice that can control when and if a method (or other join point) is executed. This is true for around advices only, so they require an argument of type ProceedingJoinPoint, whereas other advices just use a plain JoinPoint. A sample use case is to cache return values:
private SomeCache cache;
#Around("some.signature.pattern.*(*)")
public Object cacheMethodReturn(ProceedingJoinPoint pjp){
Object cached = cache.get(pjp.getArgs());
if(cached != null) return cached; // method is never executed at all
else{
Object result = pjp.proceed();
cache.put(pjp.getArgs(), result);
return result;
}
}
In this code (using a non-existent cache technology to illustrate a point) the actual method is only called if the cache doesn't return a result. This is the exact way the Spring EHCache Annotations project works, for example.
Another specialty of around advices is that they must have a return value, whereas other advice types must not have one.
#Around("execution(* com.mumz.test.spring.aop.BookShelf.addBook(..))")
It means before calling com.mumz.test.spring.aop.BookShelf.addBook method aroundAddAdvice method is called.
After
System.out.println("Book being added is : " + object); operation is completed . it will call your actual method addBook(). pjp.proceed() will call addBook() method.
Use JoinPoint with following advice types:
#Before, #After, #AfterReturning, #AfterThrowing
Use ProceedingJoinPoint with following advice type:
#Around
ProceedingJoinPoint is a JoinPoint with additional features.
ProceedingJoinPoint is used with #Around advice. #Around is very powerful advice that combines the features of rest of the Advice.
ProceedingJoinPoint::proceed is basically used to execute the original method.
Consider following example:
#Around("#annotation(com.annotations.ExecutionLoggerAround)")
public void executeLogger(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("Method execution starts at :: " + System.currentTimeMillis());
proceedingJoinPoint.proceed();
System.out.println("Method execution completes at :: " + System.currentTimeMillis());
}
#ExecutionLoggerAround
public void generateReport() {
System.out.println("Generating XLS report !!");
}
public #interface ExecutionLogger {
}
Now when you will call generateReport, Around advice will be executed. If you skip line proceedingJoinPoint.proceed(), the actual method will not be executed. You will see only those two println in the console.
PS: To understand better you need to know how AOP works. Spring creates proxy objects either using JDK proxy or CGLIB proxy. So its actually the proxied object that executes at runtime which use our method behind the scene.

Declaring an aspect on an aspect

I happen to have an #Aspect that declares a method that is intercepted by a pointcut of another aspect. The aspects are created with compile-time weaving and the container is instantiated using Spring.
I annotated my aspect with #Configurable to tell Spring that the component is being created outside the container. I happen to have a static reference to a Log object in this aspect too. To summarize, the code looks something like this
#Aspect
#Configurable
public class MyAspect {
private static final Log log = LogFactory.getClass(MyAspect.class);
// Autowired dependencies
// Pointcuts and advice
// Happens to be a pointcut of some other Advice
#Asynchronous
private Object someMethod(...) {
}
}
During AspectJ compilation, I do not see the message I expect, which looks something like this:
weaveinfo Join point 'method-call(java.lang.Object mypackage.someMethod(...))' in Type 'mypackage.MyAspect' (MyAspect.java:30) advised by around advice from 'anotherpackage.AsynchronousAspect' (from AsynchronousAspect.java))
As expected, the third-party advice is never invoked at this point. However, if I add a simple log entry to my advice, something like
log.debug("Join point invoked!");
Then the compilation happens correctly and all the aspects are wired (including my third party dependencies) and invoked correctly.
What does adding a log entry do to change my assumptions?
What you want to do is pretty straightforward and not dangerous at all if you know what you are doing. Please apologise that I am not a Spring user and that I prefer native AspectJ syntax to #AspectJ. This little sample runs just fine:
public class Application {
public static void main(String[] args) {
System.out.println("Hello world!");
someMethod();
}
private static void someMethod() {
System.out.println("Doing something ...");
}
}
public aspect FirstAspect {
void around() : execution(void *..main(..)) {
System.out.println(thisJoinPointStaticPart + ": " + someMethod("before", "main"));
proceed();
System.out.println(thisJoinPointStaticPart + ": " + someMethod("after", "main"));
}
private Object someMethod(String position, String methodName) {
return position + " " + methodName;
}
}
public aspect SecondAspect {
Object around() : execution(* *..someMethod(..)) {
System.out.println(thisJoinPointStaticPart + ": before someMethod");
Object result = proceed();
System.out.println(thisJoinPointStaticPart + ": after someMethod");
return result;
}
}
The result is as expected:
execution(Object FirstAspect.someMethod(String, String)): before someMethod
execution(Object FirstAspect.someMethod(String, String)): after someMethod
execution(void Application.main(String[])): before main
Hello world!
execution(void Application.someMethod()): before someMethod
Doing something ...
execution(void Application.someMethod()): after someMethod
execution(Object FirstAspect.someMethod(String, String)): before someMethod
execution(Object FirstAspect.someMethod(String, String)): after someMethod
execution(void Application.main(String[])): after main
If furthermore you are concerned with thhe order in which aspects are applied/executed, please use declare precedence.
If you experience problems with accessing e.g. private members, you need to use a privileged aspect.
Update: Changed usage of thisEnclosingJoinPointStaticPart to thisJoinPointStaticPart. That was just a copy & paste error. The result is the same on execution join points, but anyway the correction shows better the code's intent.

Need help creating a specific pointcut that utilizes a value from a method annotation

I have the following method
#AutoHandling(slot = FunctionalArea.PRE_MAIN_MENU)
#RequestMapping(method = RequestMethod.GET)
public String navigation(ModelMap model) {
logger.debug("navigation");
...
//First time to the Main Menu and ID-Level is ID-1 or greater
if (!callSession.getCallFlowData().isMainMenuPlayed()
&& callSession.getCallFlowData().getIdLevel() >= 1) {
// Call Auto Handling
logger.info("Call AutoHandling");
autoHandlingComponent.processAutoHandling();
}
...
return forward(returnView);
}
Basically what I want to do, is have a pointcut on processAutoHandling()
But in the #After, I need to use the slot() for #AutoHandling
I tried this, but it does not get called
#Pointcut("execution(* *.processAutoHandling())")
public void processAutoHandleCall() {
logger.debug("processAutoHandleCall");
}
#Around("processAutoHandleCall() &&" +
"#annotation(autoHandling) &&" +
"target(bean) "
)
public Object processAutoHandlingCall(ProceedingJoinPoint jp,
AutoHandling autoHandling,
Object bean)
throws Throwable {
...
You can use the wormhole design pattern for this. I am illustrating using AspectJ byte-code based approach and syntax, but you should be able to get the same effect using an explicit ThreadLocal if you are using Spring's proxy-based AOP.
pointcut navigation(AutoHandling handling) : execution(* navigation(..))
&& #annotation(handling);
// Collect whatever other context you need
pointcut processAutoHandleCall() : execution(* *.processAutoHandling());
pointcut wormhole(AutoHandling handling) : processAutoHandleCall()
&& cflow(navigation(handling));
after(AutoHandling handling) : wormhole(hanlding) {
... you advice code
... access the slot using handling.slot()
}
a) It can't work, you are trying to match two different things:
#Around("processAutoHandleCall() &&" +
"#annotation(autoHandling) &&" +
"target(bean) "
)
processHandleCall() matches the inner method execution autoHandlingComponent.processAutoHandling() while #annotation(autoHandling) matches the outer method execution navigation(ModelMap model)
b) since you are obviously trying to advise a Controller, there are a few caveats:
if you use proxy-target-class=true everything should work as is, just make sure you don't have any final methods
if you don't, all your controller methods must be backed by an interface and the #RequestMapping etc annotations must be on the interface, not the implementing class as described in this section of the Spring MVC reference docs

Categories