Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [aspectj-users] How to resolve real execution signature for call joinpoint


Actually and unfortunately, contrary to your assumption
​> ​
Signature.getDeclaringType() does not yield the same type as

​> ​
thisJoinPoint.getTarget().
getClass().

That isn't exactly what I was saying. I was saying this new method you wanted to add, how would its return value differ from thisJoinPoint.getTarget().getClass() - I know that getDeclaringType() would be different from thisJoinPoint.getTarget() since the former is based on the type referenced in the invoke instruction (it is not based on the type of the target, even if that could be statically analyzed) whilst the second is based on the runtime types flowing around. From your test program it seems you want this new method on tip to return the actual declaring class of the method involved?

It all depends what you want at the join point - as your test program shows you can dig around for whatever you want (if you really want the declaring class of the method involved, you can find it). I could push helper code into thisJoinPoint for some of this but I need concrete use cases and votes on requests for it.

cheers,
Andy





On 23 May 2014 06:20, Alexander Kriegisch <alexander@xxxxxxxxxxxxxx> wrote:
Actually and unfortunately, contrary to your assumption
Signature.getDeclaringType() does not yield the same type as
thisJoinPoint.getTarget().getClass().

Here is some sample code (also attached) demonstrating the problem. You need
Apache Commons Lang (my version is 3.3.2) in order to use ClassUtils because
I found it too tedious to deal with Class.forName(<primitive type>) by
myself:


package de.scrum_master.app;

import java.util.ArrayList;
import java.util.List;

public class MyList<E> extends ArrayList<E> {
        private static final long serialVersionUID = -8827657434447203955L;

        public MyList() { super(); }
        @Override public boolean remove(Object o) { return false; }

        public void myMethod() {}
        public int myOtherMethod(int number) { return number * number; }

        public static void main(String[] args) {
                MyList<String> myList = new MyList<>();
                myList.add("foo");
                myList.add("bar");
                myList.remove("bar");
                myList.add(0, "XXX");
                for (String element : myList)
                        System.out.println(element);
                myList.myMethod();
                myList.myOtherMethod(11);

                List<String> jdkList = new MyList<>();
                jdkList.add("one");
                jdkList.add("two");
                jdkList.remove("two");
                jdkList.add(0, "XXX");
                for (String element : jdkList)
                        System.out.println(element);
        }
}


package de.scrum_master.aspect;

import java.lang.reflect.Method;

import org.apache.commons.lang3.ClassUtils;
import org.aspectj.lang.Signature;
import org.aspectj.lang.SoftException;

public aspect MethodTracer pertarget(call(* *(..))) {
        public MethodTracer() {
                super();
                System.out.printf(
                                "%n%-60s  |  %-30s  |  %-30s  |  %-30s%n",
                                "Join point",
                                "AJ target class",
                                "AJ method declaring type",
                                "Real method declaring type"
                        );
                System.out.printf(
                                "%-60s==|==%-30s==|==%-30s==|==%-30s%n",
                                "============================================================",
                                "==============================",
                                "==============================",
                                "=============================="
                        );
        }

        before(Object target) : !within(MethodTracer) && call(* *(..)) && target(target) {
                Signature methodSignature = thisJoinPointStaticPart.getSignature();
                Method method;
                try {
                        String[] signatureParts = methodSignature.toLongString().split("[()]|, ");
                        Class<?>[] parameterTypes = new Class<?>[signatureParts.length - 1];
                        int index = -1;
                        for (String signaturePart : signatureParts) {
                                if (++index == 0)
                                        continue;
                                parameterTypes[index - 1] = ClassUtils.getClass(signaturePart);
                        }
                        method = target.getClass().getMethod(methodSignature.getName(), parameterTypes);
                } catch (ClassNotFoundException|NoSuchMethodException e) {
                        throw new SoftException(e);
                }
                System.out.printf(
                        "%-60s  |  %-30s  |  %-30s  |  %-30s%n",
                        thisJoinPointStaticPart,
                        target.getClass().getName(),
                        methodSignature.getDeclaringTypeName(),
                        method.getDeclaringClass().getName()
                );
        }
}


The output looks like this for the two lists I create in the driver class:


Join point                                                    |  AJ target class                 |  AJ method declaring type        |  Real method declaring type
==============================================================|==================================|==================================|================================
call(boolean de.scrum_master.app.MyList.add(Object))          |  de.scrum_master.app.MyList      |  de.scrum_master.app.MyList      |  java.util.ArrayList
call(boolean de.scrum_master.app.MyList.add(Object))          |  de.scrum_master.app.MyList      |  de.scrum_master.app.MyList      |  java.util.ArrayList
call(boolean de.scrum_master.app.MyList.remove(Object))       |  de.scrum_master.app.MyList      |  de.scrum_master.app.MyList      |  de.scrum_master.app.MyList
call(void de.scrum_master.app.MyList.add(int, Object))        |  de.scrum_master.app.MyList      |  de.scrum_master.app.MyList      |  java.util.ArrayList
call(Iterator de.scrum_master.app.MyList.iterator())          |  de.scrum_master.app.MyList      |  de.scrum_master.app.MyList      |  java.util.ArrayList
XXX
foo
bar
call(void de.scrum_master.app.MyList.myMethod())              |  de.scrum_master.app.MyList      |  de.scrum_master.app.MyList      |  de.scrum_master.app.MyList
call(int de.scrum_master.app.MyList.myOtherMethod(int))       |  de.scrum_master.app.MyList      |  de.scrum_master.app.MyList      |  de.scrum_master.app.MyList

Join point                                                    |  AJ target class                 |  AJ method declaring type        |  Real method declaring type
==============================================================|==================================|==================================|================================
call(boolean java.util.List.add(Object))                      |  de.scrum_master.app.MyList      |  java.util.List                  |  java.util.ArrayList
call(boolean java.util.List.add(Object))                      |  de.scrum_master.app.MyList      |  java.util.List                  |  java.util.ArrayList
call(boolean java.util.List.remove(Object))                   |  de.scrum_master.app.MyList      |  java.util.List                  |  de.scrum_master.app.MyList
call(void java.util.List.add(int, Object))                    |  de.scrum_master.app.MyList      |  java.util.List                  |  java.util.ArrayList
call(Iterator java.util.List.iterator())                      |  de.scrum_master.app.MyList      |  java.util.List                  |  java.util.ArrayList
XXX
one
two

--
Alexander Kriegisch
http://scrum-master.de


Andy Clement schrieb am 23.05.2014 02:51:

> I had a further thought about this problem whilst out on a run, I can
> imagine (although I haven't coded it up) something around and if() clause
> and using reflection with <target>.class.getDeclaredMethod(<thisJoinPoint
> stuff in here>) (and walking up the hierarchy) to check where the method
> is actually declared. Won't do much for the performance though :)
>
>
> > As for Signature.getDeclaringTypeName(), the acceptance criteria do not
> seem to involve dynamic method resolution, only static code analysis (what
> is the target's declared type?). Would it be possible to enhance that
> method, add a toggle or similarly named method for dynamic resolution?
>
>
> Currently that information is built based solely on the invoke instruction
> (static info), we're not actually looking at what is on the stack so are
> at the mercy of what the compiler decided to do. It is feasible to add a
> similar named method but isn't that just the same as asking
> thisJoinPoint.getTarget().getClass() (at least for non static methods)?
>
>
> On 22 May 2014 16:06, Alexander Kriegisch <alexander@xxxxxxxxxxxxxx
> <mailto:alexander@xxxxxxxxxxxxxx> > wrote:
>>
>> An afterthought: As for Signature.getDeclaringTypeName(), the acceptance
>> criteria do not seem to involve dynamic method resolution, only static
>> code analysis (what is the target's declared type?). Would it be possible
>> to enhance that method, add a toggle or similarly named method for
>> dynamic resolution?
>>
>>
>> Alexander Kriegisch schrieb am 23.05.2014 00:55:
>>
>> > Okay, so you had the same thoughts ('if' pointcut and stacktrace check)
>> as I
>> > and also the same results. We would need something like a sneek peek
>> towards
>> > method resolution which happens just an instant later, but not quite at
>> the
>> > call site.
>> >
>> > BTW, this was one of my experimental pointcuts:
>> >
>> > pointcut jdkType() :
>> >
>> if(thisJoinPointStaticPart.getSignature().getDeclaringTypeName().startsWith("java."));
>> >
>> > But for the reasons I mentioned on StackOverflow this does not (and
>> cannot)
>> > work reliably for two out of four cases.
>> >
>> > Thank you anyway :-)
>> >
>> >
>> > Andy Clement schrieb am 23.05.2014 00:48:
>> >
>> >> I can't immediately think of a way to do that. Even if using an if()
>> clause on
>> >> the point cut to insert a runtime test, that test can't tell whose
>> method is
>> >> running on the object you have (whether it is a local one or an
>> inherited
>> >> one). You can't even inspect the stack trace in the advice (which
>> would be
>> >> crude anyway) because the advice invocation is made at the call site
>> before
>> >> you enter the method in question.
>> >>
>> >> Incidentally I am probably going to be hanging around on stack
>> overflow more
>> >> these days so anyone posting questions here, feel free to start
>> posting there,
>> >> I will see them :)
>> >>
>> >>
>> >> On 22 May 2014 00:59, Alexander Kriegisch wrote:
>> >>
>> >>> On StackOverflow I saw an interesting question. Even though I (user
>> >>> kriegaex) have answered it as good as I could at
>> >>>
>> http://stackoverflow.com/questions/23791760/aspectj-separating-native-library-calls-from-application-calls/23799457#23799457
>> >>> ,
>> >>> I am still wondering if there might be a way to find out which method
>> a
>> >>> call really resolves to later in all of the four cases mentioned
>> there,
>> >>> because in general a call joinpoint's signature is not necessarily
>> equal
>> >>> to what gets executed later.
>> >>>
>> >>> I don't know if anyone can answer that, but my best guess would be
>> Andy
>> >>> Clement (as usual). ;-)

_______________________________________________
aspectj-users mailing list
aspectj-users@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/aspectj-users



Back to the top