The pointcut language is a tool that allows joinpoint matching. A pointcut expression determines in which joinpoint executions of the base system an advice should be invoked.
In this Chapter, we will explore the syntax of pointcut expressions.
We will also see the API used to represent a matched joinpoint during advice execution, and how this relates to pointcut expression constructs.
There are two types of wildcards you can use within pointcut expressions
Type patterns are defined by an annotation or by fully qualified class name. Annotation expressions are not allowed to have wildcards within them, but class expressions are.
To reference all subtypes of a certain class (or implementors of an interface), the $instanceof{} expression can be used. Wildcards and annotations may also be used within $instanceof{} expressions.
$instanceof{org.acme.SomeInterface} $instanceof{@org.acme.SomeAnnotation} $instanceof{org.acme.interfaces.*}
are all allowed.
For very complex type expressions, the Typedef construct can be used. To reference a Typedef within a class expression $typedef{id} is used.
public void org.acme.SomeClass->methodName(java.lang.String)
The attributes( public, static, private) of the method are optional. If the attribute is left out then any attribute is assumed. Attributes accept the ! modifier for negation.
public !static void org.acme.SomeClass->*(..)
$instanceof{} can be used in place of the class name.
void $instanceof{org.acme.SomeInterface}->methodName(java.lang.String)
To pick out all toString() methods of all classes within the org.acme package, we can use org.acme.. in place of the class name.
java.lang.String org.acme..->toString()
To only match methods from a given interface you can use the $implements{} or $implementing{} keywords in place of the method name. $implements{} only matches methods from the exact interface(s) given, while $implementing{} matches methods from the interface(s) given AND their super interfaces.
void $instanceof{org.acme.IfA}->$implements(org.acme.IfA)(..)
void $instanceof{org.acme.IfB}->$implementing(org.acme.IfA, org.acme.IfB)(..)
Annotations can be used in place of the class name. The below example matches any methodName() of a tagged @javax.ejb.Entity class.
void @javax.ejb.Entity->methodName(java.lang.String)
Annotations can be also be used in place of the method name. The below examples matches any method tagged as @javax.ejb.Tx.
* *->@javax.ejb.Tx(..)
In addition you can use typedefs, $instanceof{}, annotations and wildcards for method parameters and return types. The following matches all methods called loadEntity that return a class annotated with @javax.ejb.Entity, that takes a class (or a class whose superclass/interface is) annotated as @org.acme.Ann and any class that matches java.*.String (such as java.lang.String).
@javax.ejb.Entity *->loadEntity($instanceof{@org.acme.Ann}, java.*.String)You can also include an optional throws clause in the pointcut expression:
public void org.acme.SomeClass->methodName(java.lang.String) \ throws org.acme.SomeException, java.lang.ExceptionIf any exceptions are present in the pointcut expression they must be present in the throws clause of the methods to be matched.
public org.acme.SomeClass->new(java.lang.String)
Constructor expressions are made up of the fully qualified classname and the new keyword The attributes( public, static, private) of the method are optional. If the attribute is left out then any attribute is assumed. Attributes accept the ! modifier for negation.
!public org.acme.SomeClass->new(..)
$instanceof{} can be used in the class name.
$instanceof{org.acme.SomeInterface}->new(..)
To pick out all no-args constructors of all classes within the org.acme package, we can use org.acme.. in place of the class name.
org.acme..->new()
Annotations can be used in place of the class name. The below example matches any constructor of a tagged @javax.ejb.Entity class.
@javax.ejb.Entity->new(..)
Annotations can be also be used in place of the new keyword. The below examples matches any constructor tagged as @javax.ejb.MethodPermission.
*->@javax.ejb.MethodPermission(..)
In addition, just as for methods you can use typedefs, $instanceof{}, annotations and wildcards for constructor parameters. The following matches all constructors that take a class annotated as @org.acme.Ann and any class that matches java.*.String (such as java.lang.String).
*->new(@org.acme.Ann, java.*.String)
You can also include an optional throws clause in the pointcut expression:
public void org.acme.SomeClass->new(java.lang.String) \ throws org.acme.SomeException, java.lang.Exception
If any exceptions are present in the pointcut expression they must be present in the throws clause of the constructors to be matched.
public java.lang.String org.acme.SomeClass->fieldname
Constructor expressions are made up of the type, the fully qualified classname where the field resides and the field's name. The attributes( public, static, private) of the field are optional. If the attribute is left out then any attribute is assumed. Attributes accept the ! modifier for negation.
!public java.lang.String org.acme.SomeClass->*
$instanceof{} can be used in the class name. The below expression matches any field of any type or subtype of org.acme.SomeInterface
* $instanceof{org.acme.SomeInterface}->*
Annotations can be used in place of the class name. The below example matches any field where the type class is tagged with @javax.ejb.Entity.
* @javax.ejb.Entity->*
Annotations can be also be used in place of the field name. The below examples matches any field tagged as @org.jboss.Injected.
* *->@org.jboss.Injected
In addition, you can use typedefs, $instanceof{}, annotations and wildcards for field types. The following matches all fields where the type class has been tagged with @javax.ejb.Entity.
@javax.ejb.Entity *->*
To pick out all fields annotated with @org.foo.Transient within the org.acme package, we can use org.acme.. in place of the class name, and @org.foo.Transient in please of the field name
* org.acme..->@org.foo.Transient
Pointcuts use class, field, constructor, and method expressions to specify the actual joinpoint that should be intercepted/watched.
execution(public void Foo->method() execution(public Foo->new())
execution is used to specify that you want an interception to happen whenever a method or constructor is called. The the first example of matches anytime a method is called, the second matches a constructor. System classes cannot be used within execution expressions because it is impossible to instrument them.
construction(public Foo->new())
construction is used to specify that you want aspects to run within the constructor. The execution pointcut requires that any code that calls new() must be instrumented by the compiler. With construction the aspects are weaved right within the constructor after all the code in the constructor. The aspects are appended to the code of the constructor.
get(public int Foo->fieldname)
get is used to specify that you want an interception to happen when a specific field is accessed for a read.
get(public int Foo->fieldname)
set is used to specify that you want an interception to happen when a specific field is accessed for a write.
field(public int Foo->fieldname)
field is used to specify that you want an interception to happen when a specific field is accessed for a read or a write.
all(org.acme.SomeClass) all(@org.jboss.security.Permission)
all is used to specify any constructor, method or field of a particular class will be intercepted. If an annotation is used, it matches the member's annotation, not the class's annotation.
call(public void Foo->method() call(public Foo->new())
call is used to specify any constructor or method that you want intercepted. It is different than execution in that the interception happens at the caller side of things and the caller information is available within the Invocation object. call can be used to intercept System classes because the bytecode weaving happens within the callers bytecode.
within(org.acme.SomeClass) within(@org.jboss.security.Permission)
within matches any joinpoint (method or constructor call) within any code within a particular type.
withincode(public void Foo->method() withincode(public Foo->new())
withincode matches any joinpoint (method or constructor call) within a particular method or constructor.
has(void *->@org.jboss.security.Permission(..)) has(*->new(java.lang.String))
has is an additional requirement for matching. If a joinpoint is matched, its class must also have a constructor or method that matches the has expression.
hasfield(* *->@org.jboss.security.Permission) hasfield(public java.lang.String *->*)
has is an additional requirement for matching. If a joinpoint is matched, its class must also have a field that matches the hasfield expression.
Pointcuts can be composed into boolean expressions.
Here's some examples.
call(void Foo->someMethod()) AND withincode(void Bar->caller()) execution(* *->@SomeAnnotation(..)) OR field(* *->@SomeAnnotation)
Pointcuts can be named in XML (Chapter 5, XML Bindings) or annotation (Chapter 6, Annotation Bindings) bindings. They can be referenced directly within a pointcut expression.
some.named.pointcut OR call(void Foo->someMethod())
Sometimes, when writing pointcuts, you want to specify a really complex type they may or may not have boolean logic associated with it. You can group these complex type definitions into a JBoss AOP Typedef either in XML or as an annotation (See later in this document). Typedef expressions can also be used within introduction expressions. Typedef expressions can be made up of has, hasfield, and class expressions. class takes a fully qualified class name, or an $instanceof{} expression.
class(org.pkg.*) OR has(* *->@Tx(..)) AND !class($instanceof{org.foo.Bar})
After getting acquainted with all pointcut constructs, let's see how this reflects on the API available to advices during their execution.
JBoss AOP provides JoinPoint Beans, so that an advice can access all information regarding a joinpoint during its execution. This information consists of context values, explained in the next subsection, and of reflection objects (java.lang.reflection). The reflection objects describe the joinpoint being intercepted like a java.lang.Method for a method execution joinpoint).
There are two groups of beans. The first one is the Invocation beans group. All classes of this group are subclasses of org.jboss.aop.joinpoint.Invocation. The Invocation class was presented in Chapter 2 as a runtime encapsulation of a joinpoint. An Invocation object also contains an interceptor chain, where all advices and interceptors that intercept the joinpoint are stored. Invocation beans provide the invokeNext() method, responsible for proceeding execution to the next advice in the interceptor chain (if there is an advice that has not started execution yet) or to the joinpoint itself (if all advices contained in the interceptor chain have already started running). We will see more on this in the next chapter.
The other group of beans contains only information regarding the joinpoint itself, and are called the JoinPointBean group. All beans of this group are defined in interfaces, with org.jboss.joinpoint.JoinPointBean being their common superinterface.
The Invocation objects are available only to around advices. All other types of advices can use the JoinPointBean types to access joinpoint specific data.
In both groups there is a specific type for each joinpoint type. The type of bean corresponding to each joinpoint type can be seen in Table 3.1, “ Joinpoint Types Table ”. All beans are in the package org.jboss.aop.joinpoint.
According to the type of the joinpoint, there are specific context values available.
The context values are:
Table 3.1, “ Joinpoint Types Table ” shows what context values may be available depending on the joinpoint type.
Table 3.1. Joinpoint Types Table
Joinpoint | Pointcut Construct | Bean | ContextValues | ||||
---|---|---|---|---|---|---|---|
Invocation | JoinpointBean | Target | Caller | Arguments | Return Value | ||
field read | read, field, all | FieldReadInvocation | FieldAccess | Yes | No | No | Yes |
field write | write, field, all | FieldWriteInvocation | FieldAccess | Yes | No | Yes | No |
method execution | execution, all | MethodInvocation | MethodExecution | Yes | No | Yes | Yes |
constructor execution | execution | ConstructorInvocation | ConstructorExecution | No | No | Yes | Yes |
construction | construction | ConstructionInvocation | ConstructorExecution | Yes | No | Yes | No |
method call | call, within, withincode | CallerInvocation, MethodCalledByConstructorInvocation, MethodCalledByMethodInvocation | MethodCall, MethodCallByConstructor, MethodCallByMethod | Yes | Yes | Yes | Yes |
constructor call | call, within, withincode | CallerInvocation, ConstructorCalledByConstructorInvocation, ConstructorCalledByMethodInvocation | ConstructorCall, ConstructorCallByConstructor, ConstructorCallByMethod | Yes | Yes | Yes | Yes |