ATTENTION: Please do not remove blank lines in between 'include::' statements. Otherwise, section numbers in the
table of contents (TOC) can be wrong and the first section of each document missing completely.
////
-include::joinpointsignatures.adoc[]
+include::joinpointsignatures.adoc[Join Point Signatures]
-include::annotations.adoc[]
+include::annotations.adoc[Annotations]
-include::generics.adoc[]
+include::generics.adoc[Generics]
-include::autoboxing.adoc[]
+include::autoboxing.adoc[Autoboxing and Unboxing]
-include::covariance.adoc[]
+include::covariance.adoc[Covariance]
-include::varargs.adoc[]
+include::varargs.adoc[Varargs]
-include::enumeratedtypes.adoc[]
+include::enumeratedtypes.adoc[Enumerated Types]
-include::pertypewithin.adoc[]
+include::pertypewithin.adoc[The `pertypewithin` Aspect Instantiation Model]
-include::ataspectj.adoc[]
+include::ataspectj.adoc[An Annotation Based Development Style]
-include::reflection.adoc[]
+include::reflection.adoc[New Reflection Interfaces]
-include::miscellaneous.adoc[]
+include::miscellaneous.adoc[Other Changes in AspectJ 5]
-include::ltw.adoc[]
+include::ltw.adoc[Load-Time Weaving]
-include::grammar.adoc[]
+include::grammar.adoc[A Grammar for the AspectJ 5 Language]
[source, java]
....
-pointcut someCallWithIfTest(int i) : call(* *.*(int)) && args(i) && if(i > 0);
+pointcut someCallWithIfTest(int i) :
+ call(* *.*(int)) && args(i) && if(i > 0);
....
and the following is also a valid form:
....
@Before("call(* org.aspectprogrammer..*(..)) && this(foo)")
public void callFromFoo(JoinPoint thisJoinPoint, Foo foo) {
- System.out.println("Call from Foo: " + foo + " at "
- + thisJoinPoint);
+ System.out.println("Call from Foo: " + foo + " at " + thisJoinPoint);
}
....
[source, java]
....
before(Foo foo) : call(* org.aspectprogrammer..*(..)) && this(foo) {
- System.out.println("Call from Foo: " + foo + " at "
- + thisJoinPoint);
+ System.out.println("Call from Foo: " + foo + " at " + thisJoinPoint);
}
....
[source, java]
....
@Before("call(* org.aspectprogrammer..*(..)) && this(Foo)")
-public void callFromFoo(JoinPoint thisJoinPoint,
- JoinPoint.StaticPart thisJoinPointStaticPart,
- JoinPoint.EnclosingStaticPart thisEnclosingJoinPointStaticPart) {
+public void callFromFoo(
+ JoinPoint thisJoinPoint,
+ JoinPoint.StaticPart thisJoinPointStaticPart,
+ JoinPoint.EnclosingStaticPart thisEnclosingJoinPointStaticPart
+) {
// ...
}
....
}
....
-(Note the use of the "pointcut=" prefix in front of the pointcut
+(Note the use of the `pointcut=` prefix in front of the pointcut
expression in the returning case).
After throwing advice works in a similar fashion, using the `throwing`
....
Note that the ProceedingJoinPoint does not need to be passed to the
-proceed(..) arguments.
+`proceed(..)` arguments.
In code style, the proceed method has the same signature as the advice,
any reordering of actual arguments to the joinpoint that is done in the
advice signature must be respected. Annotation style is different. The
-proceed(..) call takes, in this order:
-
-* If 'this()' was used in the pointcut
-+
-for binding
-+
-, it must be passed first in proceed(..).
-* If 'target()' was used in the pointcut
-+
-for binding
-+
-, it must be passed next in proceed(..) - it will be the first argument
-to proceed(..) if this() was not used for binding.
-* Finally come
-+
-all
-+
-the arguments expected at the join point, in the order they are supplied
-at the join point. Effectively the advice signature is ignored - it
-doesn't matter if a subset of arguments were bound or the ordering was
-changed in the advice signature, the proceed(..) calls takes all of them
-in the right order for the join point.
-
-Since proceed(..) in this case takes an Object array, AspectJ cannot do
+`proceed(..)` call takes, in this order:
+
+* If `this()` was used in the pointcut for binding, it must be passed first in
+ `proceed(..)`.
+* If `target()` was used in the pointcut for binding, it must be passed next in
+ `proceed(..)` - it will be the first argument to `proceed(..)` if `this()`
+ was not used for binding.
+* Finally come all the arguments expected at the join point, in the order they
+ are supplied at the join point. Effectively the advice signature is ignored -
+ it doesn't matter if a subset of arguments were bound or the ordering was
+ changed in the advice signature, the `proceed(..)` calls takes all of them
+ in the right order for the join point.
+
+Since `proceed(..)` in this case takes an `Object` array, AspectJ cannot do
as much compile time checking as it can for code style. If the rules
-above aren't obeyed then it will unfortunately manifest as a runtime
+above aren't obeyed, then it will unfortunately manifest as a runtime
error.
[[ataspectj-itds]]
=== Inter-type Declarations
Inter-type declarations are challenging to support using an annotation
-style. For code style aspects compiled with the ajc compiler, the entire
+style. For code style aspects compiled with the _ajc_ compiler, the entire
type system can be made aware of inter-type declarations (new
supertypes, new methods, new fields) and the completeness and
correctness of it can be guaranteed. Achieving this with an annotation
style is hard because the source code may simply be compiled with javac
where the type system cannot be influenced and what is compiled must be
-'pure java'.
+'pure Java'.
-AspectJ 1.5.0 introduced @DeclareParents, an attempt to offer something
+AspectJ 1.5.0 introduced `@DeclareParents`, an attempt to offer something
like that which is achievable with code style declare parents and the
other intertype declarations (fields, methods, constructors). However,
it has proved too challenging to get close to the expressiveness and
-capabilities of code style in this area and effectively @DeclareParents
-is offering just a mixin strategy. The definition of mixin I am using
-here is that when some interface I is mixed into some target type T then
-this means that all the methods from I are created in T and their
+capabilities of code style in this area and effectively `@DeclareParents`
+is offering just a mixin strategy. The definition of mixin `I` am using
+here is that when some `interface I` is mixed into some target type `T` then
+this means that all the methods from `I` are created in `T` and their
implementations are simple forwarding methods that call a delegate which
-that provides an implementation of I.
+that provides an implementation of `I`.
-The next section covers @DeclareParents but AspectJ 1.6.4 introduces
-@DeclareMixin - an improved approach to defining a mixin and the choice
+The next section covers `@DeclareParents` but AspectJ 1.6.4 introduces
+`@DeclareMixin` - an improved approach to defining a mixin and the choice
of a different name for the annotation will hopefully alleviate some of
-the confusion about why @DeclareParents just doesn't offer the same
-semantics as the code style variant. Offering @DeclareMixin also gives
+the confusion about why `@DeclareParents` just doesn't offer the same
+semantics as the code style variant. Offering `@DeclareMixin` also gives
code style developers a new tool for a simple mixin whereas previously
-they would have avoided @DeclareParents thinking what it could only do
+they would have avoided `@DeclareParents`, thinking what it could only do
was already achievable with code style syntax.
-The defaultImpl attribute of @DeclareParents may become deprecated if
-@DeclareMixin proves popular, leaving @DeclareParents purely as a way to
+The `defaultImpl` attribute of `@DeclareParents` may become deprecated if
+`@DeclareMixin` proves popular, leaving `@DeclareParents` purely as a way to
introduce a marker interface.
[[atDeclareParents]]
This is very similar to the mixin mechanism supported by AspectWerkz.
The effect of the `@DeclareParents` annotation is equivalent to a
declare parents statement that all types matching the type pattern
-implement the given interface (in this case Moody). Each method declared
+implement the given interface (in this case `Moody`). Each method declared
in the interface is treated as an inter-type declaration. Note how this
scheme operates within the constraints of Java type checking and ensures
that `this` has access to the exact same set of members as in the code
style example.
-Note that it is illegal to use the @DeclareParents annotation on an
+Note that it is illegal to use the `@DeclareParents` annotation on an
aspect' field of a non-interface type. The interface type is the
inter-type declaration contract that dictates which methods are declared
on the target type.
declared method `getMoody`, the type of `this` is `Moody` (the target
type of the inter-type declaration).
-Using the annotation style this aspect can be written:
+Using the annotation style, this aspect can be written:
[source, java]
....
Although the interface type is usually determined purely from the return
type of the factory method, it can be specified in the annotation if
necessary. In this example the return type of the method extends
-multiple other interfaces and only a couple of them (I and J) should be
+multiple other interfaces and only a couple of them (`I` and `J`) should be
mixed into any matching targets:
[source, java]
=== Declare statements
The previous section on inter-type declarations covered the case of
-declare parents ... implements. The 1.5.0 release of AspectJ 5 does not
-support annotation style declarations for declare parents ... extends
-and declare soft (programs with these declarations would not in general
+`declare parents ...` implements. The 1.5.0 release of AspectJ 5 does not
+support annotation style declarations for `declare parents ... extends`
+and `declare soft` (programs with these declarations would not in general
be compilable by a regular Java 5 compiler, reducing the priority of
their implementation). These may be supported in a future release.
-Declare annotation is also not supported in the 1.5.0 release of AspectJ
-5.
+Declare annotation is also not supported in the 1.5.0 release of AspectJ 5.
Declare precedence _is_ supported. For declare precedence, use the
`@DeclarePrecedence` annotation as in the following example:
....
public aspect SystemArchitecture {
declare precedence : Security*, TransactionSupport, Persistence;
-
// ...
}
....
@DeclareError("execution(* IFoo+.*(..)) && !within(org.foo..*)")
static final String badIFooImplementorsCorrupted = getMessage();
static String getMessage() {
- return "Only foo types can implement IFoo " + System.currentTimeMillis();
+ return "Only foo types can implement IFoo " + System.currentTimeMillis();
}
....
[[ataspectj-aspectof]]
-=== aspectOf() and hasAspect() methods
+=== `aspectOf()` and `hasAspect()` methods
A central part of AspectJ's programming model is that aspects written
using the code style and compiled using ajc support `aspectOf` and
=== Autoboxing and Unboxing in Java 5
Java 5 (and hence AspectJ 1.5) supports automatic conversion of
-primitive types (int, float, double etc.) to their object equivalents
-(Integer, Float, Double,...) in assignments and method and constructor
+primitive types (`int`, `float`, `double` etc.) to their object equivalents
+(`Integer`, `Float`, `Double` etc.) in assignments and method and constructor
invocations. This conversion is know as autoboxing.
Java 5 also supports automatic unboxing, where wrapper types are
[source, java]
....
int i = 0;
-i = new Integer(5); // auto-unboxing
-
-Integer i2 = 5; // autoboxing
+i = new Integer(5); // auto-unboxing
+Integer i2 = 5; // autoboxing
....
[[autoboxing-in-aspectj5]]
words, `args(Integer)` will match any join point at which there is a
single argument of type `Integer` or of type `int`.
-* args(Integer) and args(int) are equivalent
-* args(Float) and args(float) are equivalent
-* args(Double) and args(double) are equivalent
-* args(Short) and args(short) are equivalent
-* args(Byte) and args(byte) are equivalent
-* args(Long) and args(long) are equivalent
-* args(Boolean) and args(boolean) are equivalent
+* `args(Integer)` and `args(int)` are equivalent
+* `args(Float)` and `args(float)` are equivalent
+* `args(Double)` and `args(double)` are equivalent
+* `args(Short)` and `args(short)` are equivalent
+* `args(Byte)` and `args(byte)` are equivalent
+* `args(Long)` and `args(long)` are equivalent
+* `args(Boolean)` and `args(boolean)` are equivalent
Autoboxing and unboxing are also applied when binding pointcut or advice
parameters, for example:
pointcut foo(int i) : args(i);
before(Integer i) : foo(i) {
- ...
+ // ...
}
....
`call(A B.whoAreYou())`::
Does not match anything - neither of the call join points has a
signature matched by this pattern. A lint warning is given for the
- call `a.whoAreYou()` ("does not match because declaring type is A, if
- match required use target(B)").
+ call `a.whoAreYou()` ("does not match because declaring type is `A`, if
+ match required use ``target(B)``").
`call(A+ B.whoAreYou())`::
Matches the call to `b.whoAreYou()` since the signature pattern
matches the signature `B B.whoAreYou()`. A lint warning is given for
- the call `a.whoAreYou()` ("does not match because declaring type is A,
- if match required use target(B)").
+ the call `a.whoAreYou()` ("does not match because declaring type is `A`,
+ if match required use ``target(B)``").
`call(B A.whoAreYou())`::
Does not match anything since neither join point has a signature
matched by this pattern.
enumerated types, AspectJ makes the following additional restrictions:
* You cannot use declare parents to change the super type of an enum.
-* You cannot use declare parents to declare java.lang.Enum as the parent
+* You cannot use declare parents to declare `java.lang.Enum` as the parent
of any type.
* You cannot make inter-type constructor declarations on an enum.
* You cannot extend the set of values in an enum via any ITD-like
Let `|T|` represent the erasure of some type `T`. Then:
-The erasure of a parameterized type
+* The erasure of a parameterized type `T<T1,...,Tn>` is `|T|`.
+ For example, the erasure of `List<String>` is `List`.
-T<T1,...,Tn>
+* The erasure of a nested type `T.C` is `|T|.C`.
+ For example, the erasure of the nested type `Foo<T>.Bar` is `Foo.Bar`.
-is
+* The erasure of an array type `T[]` is `|T|[]`.
+ For example, the erasure of `List<String>[]` is `List[]`.
-|T|
+* The erasure of a type variable is its leftmost bound.
+ For example, the erasure of a type variable `P` is `Object`,
+ and the erasure of a type variable `N extends Number` is `Number`.
-. For example, the erasure of
-
-List<String>
-
-is
-
-List
-
-.
-
-The erasure of a nested type
-
-T.C
-
-is
-
-|T|.C
-
-. For example, the erasure of the nested type
-
-Foo<T>.Bar
-
-is
-
-Foo.Bar
-
-.
-
-The erasure of an array type
-
-T[]
-
-is
-
-|T|[]
-
-. For example, the erasure of
-
-List<String>[]
-
-is
-
-List[]
-
-.
-
-The erasure of a type variable is its leftmost bound. For example, the
-erasure of a type variable
-
-P
-
-is
-
-Object
-
-, and the erasure of a type variable
-
-N extends Number
-
-is
-
-Number
-
-.
-
-The erasure of every other type is the type itself
+* The erasure of every other type is the type itself.
Applying these rules to the earlier examples, we find that the methods
defined in `Utils` can be matched by a signature pattern matching
....
class C {
public void foo(List<? extends Number> listOfSomeNumberType) {}
-
public void bar(List<?> listOfSomeType) {}
-
public void goo(List<Double> listOfDoubles) {}
}
....
....
`args(List)`::
- will match an execution or call join point for any of these methods
+will match an execution or call join point for any of these methods
+
`args(List<String>)`::
- will match an execution or call join point for `foo`.
+will match an execution or call join point for `foo`.
+
`args(List<Double>)`::
- matches an execution or call join point for `bar`, and _may_ match at
- an execution or call join point for `goo` since it is legitimate to
- pass an object of type `List<Double>` to a method expecting a
- `List<? extends Number>`.
- +
- In this situation a runtime test would normally be applied to
- ascertain whether or not the argument was indeed an instance of the
- required type. However, in the case of parameterized types such a test
- is not possible and therefore AspectJ 5 considers this a match, but
- issues an _unchecked_ warning. For example, compiling the aspect `A`
- below with the class `C` produces the compilation warning: "unchecked
- match of List<Double> with List<? extends Number> when argument is an
- instance of List at join point method-execution(void C.goo(List<?
- extends Number>)) [Xlint:uncheckedArgument]";
+matches an execution or call join point for `bar`, and _may_ match at
+an execution or call join point for `goo` since it is legitimate to
+pass an object of type `List<Double>` to a method expecting a
+`List<? extends Number>`.
++
+In this situation, a runtime test would normally be applied to
+ascertain whether or not the argument was indeed an instance of the
+required type. However, in the case of parameterized types such a test
+is not possible and therefore AspectJ 5 considers this a match, but
+issues an _unchecked_ warning. For example, compiling the aspect `A`
+below with the class `C` produces the compilation warning: `unchecked
+match of List<Double> with List<? extends Number> when argument is an
+instance of List at join point method-execution(void C.goo(List<?
+extends Number>)) [Xlint:uncheckedArgument]`;
[source, java]
....
From the signature of `foo` all we know is that the runtime argument
will be an instance of `Object`.Compiling this program gives the
-unchecked argument warning: "unchecked match of List<? extends Number>
+unchecked argument warning: `unchecked match of List<? extends Number>
with List when argument is an instance of List at join point
-method-execution(void C.foo(Object)) [Xlint:uncheckedArgument]". The
+method-execution(void C.foo(Object)) [Xlint:uncheckedArgument]`. The
advice will not execute at the call join point for `c.foo("hi")` since
`String` is not an instance of `List`. The advice _will_ execute at the
call join points for `c.foo(ls)` and `c.foo(ld)` since in both cases the
....
public class C {
public List<String> foo(List<String> listOfStrings) {...}
-
public List<Double> bar(List<Double> listOfDoubles) {...}
-
public List<? extends Number> goo(List<? extends Number> listOfSomeNumberType) {...}
}
....
`<T extends Number> T Utils.max(T first, T second) {...}`::
Declares a generic instance method `max` on the class `Util`. The
`max` method takes two arguments, `first` and `second` which must both
- be of the same type (and that type must be Number or a subtype of
- Number) and returns an instance of that type.
+ be of the same type (and that type must be `Number` or a subtype of
+ `Number`) and returns an instance of that type.
`static <E> E Utils.first(List<E> elements) {...}`::
Declares a static generic method `first` on the class `Util`. The
`first` method takes a list of elements of some type, and returns an
....
public aspect ASTNodeContainment extends ParentChildRelationship<ASTNode,ASTNode> {
before(ASTNode parent, ASTNode child) : addingChild(parent, child) {
- ...
+ // ...
}
}
....
As a result of this declaration, `ASTNode` gains members:
-List<ASTNode> children
-
-ASTNode parent
-
-List<ASTNode>getChildren()
-
-ASTNode getParent()
-
-void addChild(ASTNode child)
-
-void removeChild(ASTNode child)
-
-void setParent(ASTNode parent)
+* `List<ASTNode> children`
+* `ASTNode parent`
+* `List<ASTNode>getChildren()`
+* `ASTNode getParent()`
+* `void addChild(ASTNode child)`
+* `void removeChild(ASTNode child)`
+* `void setParent(ASTNode parent)`
In a system managing orders, we could declare the concrete aspect:
[source, java]
....
-public aspect OrderItemsInOrders extends ParentChildRelationship<Order, OrderItem> {
-}
+public aspect OrderItemsInOrders extends ParentChildRelationship<Order, OrderItem> {}
....
As a result of this declaration, `Order` gains members:
-List<OrderItem> children
-
-List<OrderItem> getChildren()
-
-void addChild(OrderItem child)
-
-void removeChild(OrderItem child)
+* `List<OrderItem> children`
+* `List<OrderItem> getChildren()`
+* `void addChild(OrderItem child)`
+* `void removeChild(OrderItem child)`
and `OrderItem` gains members:
-Order parent
-
-Order getParent()
-
-void setParent(Order parent)
+* `Order parent`
+* `Order getParent()`
+* `void setParent(Order parent)`
A second example of an abstract aspect, this time for handling
exceptions in a uniform manner, is shown below:
....
=== type patterns ===
-TypePattern := SimpleTypePattern |
- '!' TypePattern |
- '(' AnnotationPattern? TypePattern ')'
- TypePattern '&&' TypePattern |
- TypePattern '||' TypePattern
+TypePattern :=
+ SimpleTypePattern |
+ '!' TypePattern |
+ '(' AnnotationPattern? TypePattern ')'
+ TypePattern '&&' TypePattern |
+ TypePattern '||' TypePattern
SimpleTypePattern := DottedNamePattern '+'? '[]'*
-DottedNamePattern := FullyQualifiedName RestOfNamePattern? |
- '*' NotStarNamePattern?
+DottedNamePattern :=
+ FullyQualifiedName RestOfNamePattern? |
+ '*' NotStarNamePattern?
-RestOfNamePattern := '..' DottedNamePattern |
- '*' NotStarNamePattern?
+RestOfNamePattern := '..' DottedNamePattern | '*' NotStarNamePattern?
-NotStarNamePattern := FullyQualifiedName RestOfNamePattern? |
- '..' DottedNamePattern
+NotStarNamePattern :=
+ FullyQualifiedName RestOfNamePattern? |
+ '..' DottedNamePattern
FullyQualifiedName := JavaIdentifierCharacter+ ('.' JavaIdentifierCharacter+)*
AnnotationPattern := '!'? '@' AnnotationTypePattern AnnotationPattern*
-
-AnnotationTypePattern := FullyQualifiedName |
- '(' TypePattern ')'
+AnnotationTypePattern := FullyQualifiedName | '(' TypePattern ')'
=== signature patterns ===
-- field --
FieldPattern :=
- AnnotationPattern? FieldModifiersPattern?
- TypePattern (TypePattern DotOrDotDot)? SimpleNamePattern
+ AnnotationPattern? FieldModifiersPattern?
+ TypePattern (TypePattern DotOrDotDot)? SimpleNamePattern
FieldModifiersPattern := '!'? FieldModifier FieldModifiersPattern*
-FieldModifier := 'public' | 'private' | 'protected' | 'static' |
- 'transient' | 'final'
+FieldModifier :=
+ 'public' | 'private' | 'protected' | 'static' |
+ 'transient' | 'final'
DotOrDotDot := '.' | '..'
-- method --
MethodPattern :=
- AnnotationPattern? MethodModifiersPattern? TypePattern
- (TypePattern DotOrDotDot)? SimpleNamePattern
- '(' FormalsPattern ')' ThrowsPattern?
+ AnnotationPattern? MethodModifiersPattern? TypePattern
+ (TypePattern DotOrDotDot)? SimpleNamePattern
+ '(' FormalsPattern ')' ThrowsPattern?
MethodModifiersPattern := '!'? MethodModifier MethodModifiersPattern*
-MethodModifier := 'public' | 'private' | 'protected' | 'static' |
- 'synchronized' | 'final'
+MethodModifier :=
+ 'public' | 'private' | 'protected' | 'static' |
+ 'synchronized' | 'final'
-FormalsPattern := '..' (',' FormalsPatternAfterDotDot)? |
- OptionalParensTypePattern (',' FormalsPattern)* |
- TypePattern '...'
+FormalsPattern :=
+ '..' (',' FormalsPatternAfterDotDot)? |
+ OptionalParensTypePattern (',' FormalsPattern)* |
+ TypePattern '...'
FormalsPatternAfterDotDot :=
OptionalParensTypePattern (',' FormalsPatternAfterDotDot)* |
-- constructor --
ConstructorPattern :=
- AnnotationPattern? ConstructorModifiersPattern?
- (TypePattern DotOrDotDot)? 'new' '(' FormalsPattern ')'
- ThrowsPattern?
+ AnnotationPattern? ConstructorModifiersPattern?
+ (TypePattern DotOrDotDot)? 'new' '(' FormalsPattern ')'
+ ThrowsPattern?
-ConstructorModifiersPattern := '!'? ConstructorModifier ConstructorModifiersPattern*
+ConstructorModifiersPattern :=
+ '!'? ConstructorModifier ConstructorModifiersPattern*
ConstructorModifier := 'public' | 'private' | 'protected'
=== Pointcuts ===
PointcutPrimitive :=
- Call | Execution | Get | Set | Handler |
- Initialization | PreInitialization |
- StaticInitialization | AdviceExecution |
- This | Target | Args | CFlow | CFlowBelow |
- Within | WithinCode | If |
- AnnotationPointcut
-
-AnnotationPointcut := AtAnnotation | AtThis | AtTarget |
- AtWithin | AtWithinCode | AtArgs
+ Call | Execution | Get | Set | Handler |
+ Initialization | PreInitialization |
+ StaticInitialization | AdviceExecution |
+ This | Target | Args | CFlow | CFlowBelow |
+ Within | WithinCode | If |
+ AnnotationPointcut
+AnnotationPointcut :=
+ AtAnnotation | AtThis | AtTarget |
+ AtWithin | AtWithinCode | AtArgs
Call := 'call' '(' MethodOrConstructorPattern ')'
Identifier := JavaIdentifierChar+
FormalsOrIdentifiersPattern :=
- '..' (',' FormalsOrIdentifiersPatternAfterDotDot)? |
- TypeOrIdentifier (',' FormalsOrIdentifiersPattern)* |
- '*' (',' FormalsOrIdentifiersPattern)*
+ '..' (',' FormalsOrIdentifiersPatternAfterDotDot)? |
+ TypeOrIdentifier (',' FormalsOrIdentifiersPattern)* |
+ '*' (',' FormalsOrIdentifiersPattern)*
FormalsOrIdentifiersPatternAfterDotDot :=
- TypeOrIdentifier (',' FormalsOrIdentifiersPatternAfterDotDot)* |
- '*' (',' FormalsOrIdentifiersPatternAfterDotDot)*
+ TypeOrIdentifier (',' FormalsOrIdentifiersPatternAfterDotDot)* |
+ '*' (',' FormalsOrIdentifiersPatternAfterDotDot)*
AtAnnotation := '@annotation' '(' AnnotationOrIdentifier ')'
AtThis := '@this' '(' AnnotationOrIdentifer ')'
AtArgs := '@args' '(' AnnotationsOrIdentifiersPattern ')'
AnnotationsOrIdentifiersPattern :=
- '..' (',' AnnotationsOrIdentifiersPatternAfterDotDot)? |
- AnnotationOrIdentifier (',' AnnotationsOrIdentifiersPattern)* |
- '*' (',' AnnotationsOrIdentifiersPattern)*
+ '..' (',' AnnotationsOrIdentifiersPatternAfterDotDot)? |
+ AnnotationOrIdentifier (',' AnnotationsOrIdentifiersPattern)* |
+ '*' (',' AnnotationsOrIdentifiersPattern)*
AnnotationsOrIdentifiersPatternAfterDotDot :=
- AnnotationOrIdentifier (',' AnnotationsOrIdentifiersPatternAfterDotDot)* |
- '*' (',' AnnotationsOrIdentifiersPatternAfterDotDot)*
+ AnnotationOrIdentifier (',' AnnotationsOrIdentifiersPatternAfterDotDot)* |
+ '*' (',' AnnotationsOrIdentifiersPatternAfterDotDot)*
-PointcutDeclaration := PointcutModifiers? 'pointcut' Identifier Formals
- ':' PointcutExpression
+PointcutDeclaration :=
+ PointcutModifiers? 'pointcut' Identifier Formals ':' PointcutExpression
PointcutModifiers := PointcutModifier*
-PointcutModifier := 'public' | 'private' | 'protected' | 'abstract'
+PointcutModifier := 'public' | 'private' | 'protected' | 'abstract'
Formals := '(' ParamList? ')'
ParamList := FullyQualifiedName Identifier (',' ParamList)*
ReferencePointcut := (FullyQualifiedName '.')? Identifier Formals
-PointcutExpression := (PointcutPrimitive | ReferencePointcut) |
- '!' PointcutExpression |
- '(' PointcutExpression ')' |
- PointcutExpression '&&' PointcutExpression |
- PointcutExpression '||' PointcutExpression
+PointcutExpression :=
+ (PointcutPrimitive | ReferencePointcut) |
+ '!' PointcutExpression |
+ '(' PointcutExpression ')' |
+ PointcutExpression '&&' PointcutExpression |
+ PointcutExpression '||' PointcutExpression
=== Advice ===
[[ltw-introduction]]
=== Introduction
-See Developer's Guide for information on load-time weaving support in
-AspectJ 5.
+See xref:../devGuideDB/ltw.adoc#ltw[Developer's Guide] for information on
+load-time weaving support in AspectJ 5.
[source, java]
....
-pointcut foo(Foo foo) : (execution(* *(..)) && this(foo) ) ||
- (set(* *) && target(foo));
+pointcut foo(Foo foo) :
+ (execution(* *(..)) && this(foo) ) ||
+ (set(* *) && target(foo));
....
whereas this expression is permitted in AspectJ 5. Each context variable
....
declare soft : SomeRuntimeException : execution(* *(..));
->> "SomeRuntimeException will not be softened as it is already a RuntimeException" [XLint:runtimeExceptionNotSoftened]
+// "SomeRuntimeException will not be softened as it is already a
+// RuntimeException" [XLint:runtimeExceptionNotSoftened]
....
This XLint message can be controlled by setting the
[[pertypewithin]]
-== The pertypewithin Aspect Instantiation Model
+== The `pertypewithin` Aspect Instantiation Model
AspectJ 5 defines a new per-clause type for aspect instantiation:
`pertypewithin`. Unlike the other per-clauses, `pertypewithin` takes a
code compiled by the AspectJ 5 compiler at target level 1.5.
[[reflection_api]]
-=== Using AjTypeSystem
+=== Using `AjTypeSystem`
The starting point for using the reflection apis is
`org.aspectj.lang.reflect.AjTypeSystem` which provides the method
Java 5 (and hence AspectJ 5) allows you to specify methods that take a
variable number of arguments of a specified type. This is achieved using
-an ellipsis (...) in the method signature as shown:
+an ellipsis (`...`) in the method signature as shown:
[source, java]
....
-public void foo(int i, String... strings) {
-}
+public void foo(int i, String... strings) {}
....
A method or constructor may take at most one variable length argument,
[source, text]
....
-FormalsPattern := '..' (',' FormalsPatternAfterDotDot)? |
- OptionalParensTypePattern (',' FormalsPattern)* |
- TypePattern '...'
+FormalsPattern :=
+ '..' (',' FormalsPatternAfterDotDot)? |
+ OptionalParensTypePattern (',' FormalsPattern)* |
+ TypePattern '...'
FormalsPatternAfterDotDot :=
- OptionalParensTypePattern (',' FormalsPatternAfterDotDot)* |
- TypePattern '...'
+ OptionalParensTypePattern (',' FormalsPatternAfterDotDot)* |
+ TypePattern '...'
....
Method and constructor patterns are used in the `call`, `execution`,
`call(* org.xyz.*.*(int, String...))`::
Matches a call join point for a call to a method defined in the
- `org.xyz` package, taking an `int` and a `String vararg`.
+ `org.xyz` package, taking an `int` and a `String` _vararg_.
`execution(* org.xyz.*.*(Integer...))`::
Matches an execution join point for the execution of a method defined
- in the `org.xyz` package, taking an `Integer vararg`.
+ in the `org.xyz` package, taking an `Integer` _vararg_.
`initialization(org.xyz.*.new((Foo || Goo)...))`::
Matches the initialization join point for the construction of an
object in the `org.xyz` package via a constructor taking either a
variable number of `Foo` parameters or a variable number of `Goo`
parameters. (This example illustrating the use of a type pattern with
- ...).
+ `...`).
A variable argument parameter and an array parameter are treated as
distinct signature elements, so given the method definitions:
[source, java]
....
-public void foo(int i, String... strings) {
-}
+public void foo(int i, String... strings) {}
....
The call or execution join points for `foo` will be matched by the
parameters.
Note: the proposal in this section does not allow you to distinguish
-between a join point with a signature (int, String...) and a join point
-with a signature (int, String[]) based _solely_ on the use of the `args`
+between a join point with a signature `(int, String...)` and a join point
+with a signature `(int, String[])` based _solely_ on the use of the `args`
pointcut designator. If this distinction is required, `args` can always
be coupled with `call` or `execution`.
[source, java]
....
-pointcut setter(): target(Point) &&
- (call(void setX(int)) ||
- call(void setY(int)));
+pointcut setter():
+ target(Point) &&
+ (call(void setX(int)) || call(void setY(int)));
....
picks out each call to `setX(int)` or `setY(int)` when called on an
no-argument `main` method::
`cflow(call(void Test.main()))`
-Pointcuts compose through the operations `or` ("`||`"), `and` ("`&&`")
-and `not` ("`!`").
+Pointcuts compose through the operations `OR` (`||`), `ANT` (`&&`)
+and `NOT` (`!`).
* It is possible to use wildcards. So
[arabic]
. `target(Point) && call(int *())`
. `call(* *(..)) && (within(Line) || within(Point))`
. `within(*) && execution(*.new(int))`
-. `
- !this(Point) && call(int *(..))
- `
+. `!this(Point) && call(int *(..))`
+
means (1) any call to an `int` method with no arguments on an instance
of `Point`, regardless of its name, (2) any call to any method where the
[arabic]
. `call(public * *(..))`
. `execution(!static * *(..))`
-. ` execution(public !static * *(..))`
+. `execution(public !static * *(..))`
+
which means (1) any call to a public method, (2) any execution of a
non-static method, and (3) any execution of a public, non-static method.
Firstly, the lexical pointcut declarations `within` and `withincode`
match differently. At a call join point, the enclosing code is that of
-the call site. This means that `call(void m())
- && withincode(void m())` will only capture directly recursive
+the call site. This means that `call(void m()) && withincode(void m())`
+will only capture directly recursive
calls, for example. At an execution join point, however, the program is
already executing the method, so the enclosing code is the method
-itself: `execution(void m())
- && withincode(void m())` is the same as `execution(void m())`.
+itself: `execution(void m()) && withincode(void m())` is the same as
+`execution(void m())`.
Secondly, the call join point does not capture super calls to non-static
methods. This is because such super calls are different in Java, since
primitive pointcuts like `cflow` and `cflowbelow`. Here's an example:
`cflow(P)` picks out each join point in the control flow of the join
-points picked out by <P>. So, pictorially:
+points picked out by `P`. So, pictorially:
[source, text]
....
\
....
-What does `cflow(P) &&
- cflow(Q)` pick out? Well, it picks out each join point that is
-in both the control flow of <P> and in the control flow of <Q>. So...
+What does `cflow(P) && cflow(Q)` pick out? Well, it picks out each join point that is
+in both the control flow of `P` and in the control flow of `Q`. So...
[source, text]
....
\ \
....
-Note that <P> and <Q> might not have any join points in common... but
+Note that `P` and `Q` might not have any join points in common... but
their control flows might have join points in common.
-But what does `cflow(P
- && Q)` mean? Well, it means the control flow of those join
-points that are both picked out by <P> and picked out by <Q>.
+But what does `cflow(P && Q)` mean? Well, it means the control flow of those join
+points that are both picked out by `P` and picked out by `Q`.
[source, text]
....
\
....
-and if there are _no_ join points that are both picked by <P> and picked
-out by <Q>, then there's no chance that there are any join points in the
-control flow of `(P &&
- Q)`.
+and if there are _no_ join points that are both picked by `P` and picked
+out by `Q`, then there's no chance that there are any join points in the
+control flow of `(P && Q)`.
Here's some code that expresses this.
[source, java]
....
-pointcut setter(): target(Point) &&
- (call(void setX(int)) ||
- call(void setY(int)));
+pointcut setter():
+ target(Point) &&
+ (call(void setX(int)) || call(void setY(int)));
....
As we've seen, this pointcut picks out each call to `setX(int)` or
`setY(int)` methods where the target is an instance of `Point`. The
-pointcut is given the name `setters` and no parameters on the left-hand
+pointcut is given the name `setter` and no parameters on the left-hand
side. An empty parameter list means that none of the context from the
join points is published from this pointcut. But consider another
version of version of this pointcut definition:
[source, java]
....
-pointcut setter(Point p): target(p) &&
- (call(void setX(int)) ||
- call(void setY(int)));
+pointcut setter(Point p):
+ target(p) &&
+ (call(void setX(int)) || call(void setY(int)));
....
This version picks out exactly the same join points. But in this
[source, java]
....
-pointcut testEquality(Point p): target(Point) &&
- args(p) &&
- call(boolean equals(Object));
+pointcut testEquality(Point p):
+ target(Point) &&
+ args(p) &&
+ call(boolean equals(Object));
....
This pointcut also has a parameter of type `Point`. Similar to the
-`setters` pointcut, this means that anyone using this pointcut has
+`setter` pointcut, this means that anyone using this pointcut has
access to a `Point` from each join point. But in this case, looking at
the right-hand side we find that the object named in the parameters is
not the target `Point` object that receives the call; it's the argument
[source, java]
....
-pointcut testEquality(Point p1, Point p2): target(p1) &&
- args(p2) &&
- call(boolean equals(Object));
+pointcut testEquality(Point p1, Point p2):
+ target(p1) &&
+ args(p2) &&
+ call(boolean equals(Object));
....
-Let's look at another variation of the `setters` pointcut:
+Let's look at another variation of the `setter` pointcut:
[source, java]
....
-pointcut setter(Point p, int newval): target(p) &&
- args(newval) &&
- (call(void setX(int)) ||
- call(void setY(int)));
+pointcut setter(Point p, int newval):
+ target(p) &&
+ args(newval) &&
+ (call(void setX(int)) || call(void setY(int)));
....
In this case, a `Point` object and an `int` value are exposed by the
[source, java]
....
pointcut badPointcut(Point p1, Point p2):
- (target(p1) && call(void setX(int))) ||
- (target(p2) && call(void setY(int)));
+ (target(p1) && call(void setX(int))) ||
+ (target(p2) && call(void setY(int)));
....
because `p1` is only bound when calling `setX`, and `p2` is only bound
designator: kinded, scoping and context:
* Kinded designators are those which select a particular kind of join
-point. For example: execution, get, set, call, handler
+point. For example: `execution, get, set, call, handler`
* Scoping designators are those which select a group of join points of
-interest (of probably many kinds). For example: within, withincode
+interest (of probably many kinds). For example: `within, withincode`
* Contextual designators are those that match (and optionally bind)
-based on context. For example: this, target, @annotation
+based on context. For example: `this, target, @annotation`
A well written pointcut should try and include at least the first two
types (kinded and scoping), whilst the contextual designators may be
[source, java]
....
-pointcut setter(Point p1, int newval): target(p1) && args(newval)
- (call(void setX(int) ||
- call(void setY(int)));
+pointcut setter(Point p1, int newval):
+ target(p1) && args(newval)
+ (call(void setX(int) || call(void setY(int)));
before(Point p1, int newval): setter(p1, newval) {
- System.out.println("About to set something in " + p1 +
- " to the new value " + newval);
+ System.out.println(
+ "About to set something in " + p1 +
+ " to the new value " + newval
+ );
}
....
[source, java]
....
-before(Point p1, int newval): target(p1) && args(newval)
- (call(void setX(int)) ||
- call(void setY(int))) {
- System.out.println("About to set something in " + p1 +
- " to the new value " + newval);
+before(Point p1, int newval):
+ target(p1) && args(newval)
+ (call(void setX(int)) || call(void setY(int)))
+{
+ System.out.println(
+ "About to set something in " + p1 +
+ " to the new value " + newval
+ );
}
....
[source, java]
....
before(Point p, int x): target(p) && args(x) && call(void setX(int)) {
- if (!p.assertX(x)) return;
+ if (!p.assertX(x)) return;
}
....
[source, java]
....
-after(Point p, int x): target(p) && args(x) && call(void setX(int)) {
- if (!p.assertX(x)) throw new PostConditionViolation();
+after(Point p, int x):
+ target(p) && args(x) && call(void setX(int))
+{
+ if (!p.assertX(x)) throw new PostConditionViolation();
}
....
[source, java]
....
-after(Point p) returning(int x): target(p) && call(int getX()) {
- System.out.println("Returning int value " + x + " for p = " + p);
+after(Point p) returning(int x):
+ target(p) && call(int getX())
+{
+ System.out.println("Returning int value " + x + " for p = " + p);
}
....
[source, java]
....
-after() throwing(Exception e): target(Point) && call(void setX(int)) {
+after() throwing(Exception e):
+ target(Point) && call(void setX(int))
+{
System.out.println(e);
}
....
[source, java]
....
-void around(Point p, int x): target(p)
- && args(x)
- && call(void setX(int)) {
- if (p.assertX(x)) proceed(p, x);
- p.releaseResources();
+void around(Point p, int x):
+ target(p)
+ && args(x)
+ && call(void setX(int))
+{
+ if (p.assertX(x)) proceed(p, x);
+ p.releaseResources();
}
....
....
[[language-thisJoinPoint]]
-=== thisJoinPoint
+=== `thisJoinPoint`
AspectJ provides a special reference variable, `thisJoinPoint`, that
contains reflective information about the current join point for the
A `ThrowsClausePattern` is a comma-separated list of ``ThrowsClausePatternItem``s, where
-`ThrowsClausePatternItem`: ::
- `[ ! ] TypeNamePattern`
+[source, text]
+....
+ThrowsClausePatternItem := [ ! ] TypeNamePattern
+....
A `ThrowsClausePattern` matches the `throws` clause of any code member
signature. To match, each `ThrowsClausePatternItem` must match the