Join GitHub today
GitHub is home to over 40 million developers working together to host and review code, manage projects, and build software together.Sign up
Spring AOP's implementation of AspectJ's JoinPoint.Static part does not comply with AspectJ spec (not 'static', id always 0) [SPR-13865] #18438
AspectJ's JoinPoint.StaticPart interface defines a separate object which is meant to be a singleton style reference to that join point, independent of the currently intercepted execution state (thus the 'static part' in name.) Within this interface is a method, int getId(), which should...
The intent of the static part and the id method is to permit faster access to 'static' information about the location of the join point independent of the execution state (thread, parameters, etc). This static information is handy for logging and necessary for creating unique cache keys.
Take for example this use case: Create, using AOP, an aspect that counts and logs the execution of any request handler method on a per handler method basis.
The implementation will likely contain a Map<handler,Integer> to track the count per handler. However, as is, the static part can not be used as a key. Nor can the result of the id method be used as an intra-type method id.
Juergen Hoeller commented
Any suggestion for what we should be returning instead of 0 here? An instance-specific count value doesn't seem to deliver any benefit either, since every individual method invocation would have its own value there...
Russell Allen commented
I did quote the JavaDoc there, but I have to admit, that's not what triggered me to open the ticket. In my use case, I need to cache a bunch of introspected data about the join point. Data such as method name, return type, arguments, annotations on or up the hierarchy, etc. These are costly to compute and they don't change as the program executes. Thus the need to cache, and to have a readily available cache key. As is, I have to cast the join point and pull out the target method, being careful of proxies and interfaces, and use the java Method reference as a key.
In short, I'm more interested in the StaticPart meeting it's javaDoc semantics; that I can use a reference to the StaticPart as a cache key.
That being said, here's my thoughts on the id number: I'm not sure I understand exactly what the definition of that id is. Does "advised type" mean a Class, or is "type" being used more loosely to mean any advisable structure such as a method, field, etc.? I'm going to assume it means a java.lang.Class<?> because that makes some sense. Then each Class has an id sequence, starting at 0, from which it assigns id values to any JoinPoint within that Class's static structure. For example, if class Foo has a property bar with get and set methods, then their might be a join point (id=0) on the field bar, join point (id=1) on method getBar(), and a join point (id=2) on the method setBar(T bar).
Some key points here...
Clarification on that last point: Lets say I have a method called homepage() which is annotated with
That's my thoughts, but I'm by no means an AOP expert. It'd be great if an AspectJ team member could lend us some, uh, advice. Pun intended.
Andy Clement commented
Not sure if you have seen it but some extra discussion on this feature is in the README for 1.6.4 ( https://eclipse.org/aspectj/doc/released/README-164.html ) and AspectJ bug 89009 ( https://bugs.eclipse.org/bugs/show_bug.cgi?id=89009 ). The README does include some sample code on usage which shows using getId() as an array index, using a pertypewithin aspect to have the array in place per advised type/class:
Much faster than having the timerArray as a map:
(Advised type is a class, as you were assuming).
Matching/Advising works in AspectJ by running over the byte code in potential classes and creating join points. Then attempting to match these join points against pointcuts, if they match then inserting calls to the advice. So for any join point (e.g. a method execution) if it matches any number of pointcuts, they will all be matches on the same join point object. So in your situation if you match a join point execution via wildcard in one pointcut and via annotation matching in another pointcut, it is the same join point and in both advices attached to the pointcuts getId() will return the same number.
Basically yes, but the field itself is not a join point - only the access or modification of the field is a join point. Let's turn your sentence into a program Foo.java:
If we compile that, at compile time the join points are computed, matched against pointcuts and ids allocated. Now if we run it:
We can see that each one gets a different ID. Nothing should really be inferred that they are printed in the order 1,0,3,2 here. The numbers are allocated simply based on the order in which the byte code is processed, in this case we are processing method bodies (so computing join points for byte codes like getfield/putfield) before creating the join points representing method execution. What is important here is each distinct join point gets a different ID. Notice also that the second pointcut matches either the get or set of the field and those are different join points, so this same advice can run with different join point instances. I hope some of that helps.