Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [aspectj-users] JoinPoint.getArgs() in multiple aspects on same joinpoint

Jay,

This was asked not so long ago on the list - it should be added to a
FAQ if it is not already there, and perhaps justifies a JavaDoc
clarficiation.

See also:

http://aspectj.2085585.n4.nabble.com/Modifying-parameters-in-more-than-one-aspect-providing-around-advice-td4650584.html
http://stackoverflow.com/questions/12843998/modifying-parameters-in-more-than-one-aspect-providing-around-advice

The behaviour you are seeing is expected, but perhaps not obvious.
They key is that JoinPoint.getArgs() only returns a _copy_ of the
_original_ method arguments at the join-point.  So modifying them in a
prior aspect and/or reading them in a subsequent aspect will not do
what you want.

As mentioned by Alexander on the other thread and per his
code-example, you cannot use getArgs() to do what you want - you need
to instead bind arguments using args() in your pointcut, and then
access the arguments via the formal parameter instead of getArgs(),
e.g. in your FirstAspect:

@Pointcut("execution(@SomeAnnotation * *.foo(..)) && args(myArg)")
public void anyFoo(Object myArg) {}

@Around("anyFoo(myArg)")
public Object doAdvice(ProceedingJoinPoint jp, Object myArg) throws Throwable{
  // ...
  if (myArgs instanceof BadArg) {
    System.out.println("replaced BadArg");
    myArg = new GoodArg();
  }
  return jp.proceed(new Object[] {myArg});
}

.. then in your SecondAspect, bind myArg in the same fashion to read
the replaced argument.  This should make the code work in the way you
expect.

Brett


On 14 April 2013 16:35, Jay Roberts <pudakai@xxxxxxxxx> wrote:
> Hi,
>
> I have a situation where I have several possibly cascading Around advices as simplified below.
>
> @Aspect
> @Precedence(FirstAspect, *)
> class FirstAspect{
>         @Around("execution(@SomeAnnotation * *.foo(..))")
>         public Object doAdvice(ProceedingJoinpoint jp) throws Throwable{
>                 Object [] args = jp.getArgs();
>                 for(int i=0;i<args.length : i++){
>                         if(args[i] instanceof BadArg){
>                                 args[i] = new GoodArg();
>                         }
>                 }
>                 jp.proceed(args);
>         }
> }
>
> @Aspect
> class SecondAspect{
>         @Around("execution(@SomeAnnotation * *(..))")
>         public Object doAdvice(ProceedingJoinpoint jp) throws Throwable{
>                 Object [] args = jp.getArgs();
>                 // Gets the same args as returned from jp.getArgs() in FirstAspect,
>                 // not the modified ones.
>
>                 …. do something but have BadArg instead of GoodArg…..
>
>                 jp.proceed();
>         }
> }
>
> FirstAspect may or may not appear before SecondAspect, SecondAspect is narrower.  I traced through the aspectj source and debugger, and I saw that both FirstAspect and SecondAspect have the same join point, whose args remain the original args passed in the target method call.  The args passed in to proceed I see go into state for the AroundClosures and the ones modified in FirstAspect do make it to the target method foo.  FirstAspect is correctly executing before SecondAspect.
>
> I also see that JoinPoint.getArgs returns a copy of args rather than a reference.  And I've read a whole bunch on the web about binding args inside the join point using args.  However, this binding requires some name/pattern, and both FirstAspect, SecondAspect match to any method params (..).
>
> So how can I modify things such that downstream aspects of FirstAspect will get the modified args passed by FirstAspect to JoinPoint.proceed?  Is there a way in the advice matching to bind to args(..) so I can get it as a reference in FirstAspect?  Or, can SecondAspect somehow get the AroundClosure state so it can look at those rather than JoinPoint.getArgs()?
>
> In the meantime, I've just setup a globally accessible ThreadLocal<Map<JoinPoint, Object[]> variable that aspects (possibly) downstream of FirstAspect can lookup modified args and use those if they exist rather than the JoinPoint.getArgs().  This is pretty clunky workaround for the moment, I feel I am really missing something here.
>
> Any help would be appreciated.
>
> Thanks1
>
> Jay Roberts
> _______________________________________________
> aspectj-users mailing list
> aspectj-users@xxxxxxxxxxx
> https://dev.eclipse.org/mailman/listinfo/aspectj-users


Back to the top