Christian
Christian

Reputation: 6430

Reading and understanding AspectJ pointcuts?

/* 0 */ pointcut services(Server s): target(s) && call(public * *(..))

This pointcut, named services, picks out those points in the execution of the program when Server objects have their public methods called. It also allows anyone using the services pointcut to access the Server object whose method is being called. (taken from https://eclipse.org/aspectj/doc/released/progguide/language-anatomy.html)

I'm trying to understand AspectJ's pointcuts, and am quite a bit confused at the moment. My main question is: how do you read the above pointcut, and how do you "puzzle" its meaning together?

To illustrate my confusion, let's try to build things up from scratch:

The following pointcut would intercept all public method calls to any object, right?

/* 1 */ pointcut services() : call(public * *(..))

Now, what about this:

/* 2 */ pointcut services() : call(public * Server.*(..)) 

I assume that would intercept any points when public methods of the Server object are called.

Now, how do I get from here to the initial example 0? And how do I read it?

Would you first provide the parameter list when building the pointcut up?

/* 3a */ pointcut services(Server s) : call(public * *(..))

Is that the same as number 2 above? (I have a feeling it wouldn't work, and if it did, it would "intercept" every public method call, just like number 1.) Anyway, would the following be the same? (I'm not "capturing" s with a native pointcut yet, so I can't really define it, can I?)

/* 4a */ pointcut services(Server /* only type, no variable */) : call(public * *(..))

Or would you start by specifying a native pointcut, to "capture" the target object, like so:

/* 3b */ pointcut services() : target(s) && call(public * *(..))

I suppose that would still intercept all public method calls on any object?

Would the following work to only intercept calls on the Server object, and to "capture" that object (without making it available to be passed on later, e.g. to an advice)?

/* 5 */ pointcut services(/*nothing here*/) : target(s) && call(public * Server.*(..))

Now, going back to the original pointcut:

/* 0 */ pointcut services(Server s): target(s) && call(public * *(..))

Is that the same as

/* 6 */ pointcut services(Server s): target(s) && call(public * Server.*(..))

So, to summarize: How do you start deciphering 0?

Do you first look at the target pointcut, then at the paramter type of the services pointcut and read it "inside out"/"from right to left"? Or do you look at the parameter list first, and then look into the services pointcut to see where the argument came from (i.e. target(s))?

Or am I making this far too complicated? Am I missing an important bit somewhere to help me understand this?

Edit: the manual explains it left to right - but where does the argument to parameter Server s come from if I haven't "executed" target(s) yet?

Upvotes: 3

Views: 628

Answers (1)

Frank Pavageau
Frank Pavageau

Reputation: 11705

1: Yes, it intercepts any public method call.

2: It intercepts any public method call on an object declared as a Server, whereas 0 intercepts any public call on an object which is an instance of a Server. See the semantics.

3a: As s is not bound, it doesn't compile:

[ERROR] formal unbound in pointcut
        .../src/main/aspect/MyAspect.aj:18
pointcut services(Server s): call(public * *(..));

4a: The syntax is not valid, just like you need to name parameters when declaring methods in an interface:

[ERROR] Syntax error, insert "... VariableDeclaratorId" to complete FormalParameterList
        .../src/main/aspect/MyAspect.aj:18
pointcut services(Server): call(public * *(..));
                  ^

3b: It's not valid either, s hasn't been declared:

[WARNING] no match for this type name: s [Xlint:invalidAbsoluteTypeName]
        .../src/main/aspect/MyAspect.aj:18
pointcut services(): target(s) && call(public * *(..));

5: Like 3b, s hasn't been declared.

6: It's not the same as 0, it only matches public Server method calls (i.e. declared in Server) to a Server instance.

I have illustrated the different cases in a Github repository: switch between the branches to try them. There's an extra case in the aspect7 branch, based on 6, where I override hashCode() in Server.

You can (and should) try yourself, to get a better understanding.


To answer your final question, the argument to the pointcut comes from the fact that we want to (be able to) access the target of the call in the advice, by having it supplied as a parameter to the advice. The signature of the advice needs to contain parameters for all the referenced pointcuts, and the pointcut parameters need to reference parameters in the advice.

So, to have a Server parameter in the advice, I need it in the pointcut, and it needs to be bound to something in the pointcut definition.

Upvotes: 4

Related Questions