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

Hi Brett,

Thanks for the links and the response.  I had come across that discussion, but it still didn't meet my needs.

I understand the logic of getArgs returning the original passed args, those semantics makes sense.

But what I can't do is have something like  args(..) in the pointcut and bind to the entire set of arguments.  We don't need just one or two of them, we need all of them brought into scope and bound then so that downstream aspects may act upon what changes we may make.

The usage of our aspects are across a wide array of method signatures and we want to examine all of them via reflection, etc, making decisions about what to do for each based upon a number of factors.  We don't know which of the params will need modification, replacement in advance, so we would have to write a whole bunch of point cuts to try to cover this.

Something that would let us bind to all the arguments as, say, an object array 

@Around("execution( @anno * *(..) && args(..)")
public Object myAdvice(ProceedingJoinPoint jp, Object[] args){
     …….
}

Or, and it would be useful, the ability for an aspect to access, at least in a read only way, the current state of the closure - if it needs to be modified, jp.proceed(Object[]) already takes care of that.  That would actually allow trailing aspects to understand not just what arguments were originally passed to the method, but what ones the closure is going to actually execute on and do this comprehensively for all arguments.  It seems like that is very relevant information for certain aspects, at least in my limited experience.

So I appreciate sending on those links, but they really don't help with this situation.  

I did come up w/a very clunky workaround for our stuff, but I'm thinking that maybe I'll go back and write an aspect on JoinPointImpl that exposes the information that we need in our downstream aspects and allows us to have concise code for upstream aspect.

Again, thanks for the response, I think AspectJ is terrifically cool, I've used it on and off over the years, great stuff.

Best,

Jay Roberts

Seems like a natural extension of 
On Apr 14, 2013, at 10:00 PM, Brett Randall <javabrett@xxxxxxxxx> wrote:

> 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
> _______________________________________________
> aspectj-users mailing list
> aspectj-users@xxxxxxxxxxx
> https://dev.eclipse.org/mailman/listinfo/aspectj-users



Back to the top