diff options
Diffstat (limited to 'docs/progGuideDB/semantics.adoc')
-rw-r--r-- | docs/progGuideDB/semantics.adoc | 2176 |
1 files changed, 0 insertions, 2176 deletions
diff --git a/docs/progGuideDB/semantics.adoc b/docs/progGuideDB/semantics.adoc deleted file mode 100644 index 0cb513ad0..000000000 --- a/docs/progGuideDB/semantics.adoc +++ /dev/null @@ -1,2176 +0,0 @@ -[[semantics]] -== Language Semantics - -[[semantics-intro]] -=== Introduction - -AspectJ extends Java by overlaying a concept of join points onto the -existing Java semantics and adding a few new program elements to Java: - -A join point is a well-defined point in the execution of a program. -These include method and constructor calls, field accesses and others -described below. - -A pointcut picks out join points, and exposes some of the values in the -execution context of those join points. There are several primitive -pointcut designators, and others can be named and defined by the -`pointcut` declaration. - -A piece of advice is code that executes at each join point in a -pointcut. Advice has access to the values exposed by the pointcut. -Advice is defined by `before`, `after`, and `around` declarations. - -Inter-type declarations form AspectJ's static crosscutting features, -that is, is code that may change the type structure of a program, by -adding to or extending interfaces and classes with new fields, -constructors, or methods. Some inter-type declarations are defined -through an extension of usual method, field, and constructor -declarations, and other declarations are made with a new `declare` -keyword. - -An aspect is a crosscutting type that encapsulates pointcuts, advice, -and static crosscutting features. By type, we mean Java's notion: a -modular unit of code, with a well-defined interface, about which it is -possible to do reasoning at compile time. Aspects are defined by the -`aspect` declaration. - -[[semantics-joinPoints]] -=== Join Points - -While aspects define types that crosscut, the AspectJ system does not -allow completely arbitrary crosscutting. Rather, aspects define types -that cut across principled points in a program's execution. These -principled points are called join points. - -A join point is a well-defined point in the execution of a program. The -join points defined by AspectJ are: - -Method call:: - When a method is called, not including super calls of non-static - methods. -Method execution:: - When the body of code for an actual method executes. -Constructor call:: - When an object is built and that object's initial constructor is - called (i.e., not for `super` or `this` constructor calls). The object - being constructed is returned at a constructor call join point, so its - return type is considered to be the type of the object, and the object - itself may be accessed with `after returning` advice. -Constructor execution:: - When the body of code for an actual constructor executes, after its - this or super constructor call. The object being constructed is the - currently executing object, and so may be accessed with the `this()` pointcut. - The constructor execution join point for a constructor that - calls a super constructor also includes any non-static initializers of - enclosing class. No value is returned from a constructor execution - join point, so its return type is considered to be `void`. -Static initializer execution:: - When the static initializer for a class executes. No value is returned - from a static initializer execution join point, so its return type is - considered to be `void`. -Object pre-initialization:: - Before the object initialization code for a particular class runs. - This encompasses the time between the start of its first called - constructor and the start of its parent's constructor. Thus, the - execution of these join points encompass the join points of the - evaluation of the arguments of `this()` and `super()` constructor calls. - No value is returned from an object pre-initialization join point, so its - return type is considered to be `void`. -Object initialization:: - When the object initialization code for a particular class runs. This - encompasses the time between the return of its parent's constructor - and the return of its first called constructor. It includes all the - dynamic initializers and constructors used to create the object. The - object being constructed is the currently executing object, and so may - be accessed with the `this()` pointcut. No value is returned from a constructor - execution join point, so its return type is considered to be `void`. -Field reference:: - When a non-constant field is referenced. [Note that references to - constant fields (static final fields bound to a constant string object - or primitive value) are not join points, since Java requires them to - be inlined.] -Field set:: - When a field is assigned to. Field set join points are considered to - have one argument, the value the field is being set to. No value is - returned from a field set join point, so its return type is considered - to be void. [Note that the initializations of constant fields (`static final` - fields where the initializer is a constant string object or - primitive value) are not join points, since Java requires their - references to be inlined.] -Handler execution:: - When an exception handler executes. Handler execution join points are - considered to have one argument, the exception being handled. No value - is returned from a field set join point, so its return type is - considered to be void. -Advice execution:: - When the body of code for a piece of advice executes. - -Each join point potentially has three pieces of state associated with -it: the currently executing object, the target object, and an object -array of arguments. These are exposed by the three state-exposing -pointcuts, `this`, `target`, and `args`, respectively. - -Informally, the currently executing object is the object that a `this` -expression would pick out at the join point. The target object is where -control or attention is transferred to by the join point. The arguments -are those values passed for that transfer of control or attention. - -[cols=",,,",options="header",] -|=== -|*Join Point* |*Current Object* |*Target Object* |*Arguments* -|Method Call |executing object* |target object** |method arguments - -|Method Execution |executing object* |executing object* |method -arguments - -|Constructor Call |executing object* |None |constructor arguments - -|Constructor Execution |executing object |executing object |constructor -arguments - -|Static initializer execution |None |None |None - -|Object pre-initialization |None |None |constructor arguments - -|Object initialization |executing object |executing object |constructor -arguments - -|Field reference |executing object* |target object** |None - -|Field assignment |executing object* |target object** |assigned value - -|Handler execution |executing object* |executing object* |caught -exception - -|Advice execution |executing aspect |executing aspect |advice arguments -|=== - -+++*+++ There is no executing object in static contexts such as static method -bodies or static initializers. - -+++**+++ There is no target object for join points associated with static -methods or fields. - -[[semantics-pointcuts]] -=== Pointcuts - -A pointcut is a program element that picks out join points and exposes -data from the execution context of those join points. Pointcuts are used -primarily by advice. They can be composed with boolean operators to -build up other pointcuts. The primitive pointcuts and combinators -provided by the language are: - -`call(MethodPattern)`:: - Picks out each method call join point whose signature matches `_MethodPattern_`. -`execution(MethodPattern)`:: - Picks out each method execution join point whose signature matches `_MethodPattern_`. -`get(FieldPattern)`:: - Picks out each field reference join point whose signature matches `_FieldPattern_`. [Note that references to constant fields (static final fields bound - to a constant string object or primitive value) are not join points, - since Java requires them to be inlined.] -`set(FieldPattern)`:: - Picks out each field set join point whose signature matches `_FieldPattern_`. [Note that the initializations of constant fields (static final - fields where the initializer is a constant string object or primitive - value) are not join points, since Java requires their references to be - inlined.] -`call(ConstructorPattern)`:: - Picks out each constructor call join point whose signature matches `_ConstructorPattern_`. -`execution(ConstructorPattern)`:: - Picks out each constructor execution join point whose signature - matches `_ConstructorPattern_`. -`initialization(ConstructorPattern)`:: - Picks out each object initialization join point whose signature - matches `_ConstructorPattern_`. -`preinitialization(ConstructorPattern)`:: - Picks out each object pre-initialization join point whose signature - matches `_ConstructorPattern_`. -`staticinitialization(TypePattern)`:: - Picks out each static initializer execution join point whose signature - matches `_TypePattern_`. -`handler(TypePattern)`:: - Picks out each exception handler join point whose signature matches `_TypePattern_`. -`adviceexecution()`:: - Picks out all advice execution join points. -`within(TypePattern)`:: - Picks out each join point where the executing code is defined in a - type matched by `_TypePattern_`. -`withincode(MethodPattern)`:: - Picks out each join point where the executing code is defined in a - method whose signature matches `_MethodPattern_`. -`withincode(ConstructorPattern)`:: - Picks out each join point where the executing code is defined in a - constructor whose signature matches `_ConstructorPattern_`. -`cflow(Pointcut)`:: - Picks out each join point in the control flow of any join point `_P_` picked out by `_Pointcut_` , including `_P_` itself. -`cflowbelow(Pointcut)`:: - Picks out each join point in the control flow of any join point `_P_` picked out by `_Pointcut_`, but not `_P_` itself. -`this(Type or Id)`:: - Picks out each join point where the currently executing object (the - object bound to `_this_`) is an instance of `_Type_` , or of the type of the identifier `_Id_` (which must be bound in the enclosing advice or pointcut definition). - Will not match any join points from static contexts. -`target(Type or Id)`:: - Picks out each join point where the target object (the object on which - a call or field operation is applied to) is an instance of `_Type_` , or of the type of the identifier `_Id_` (which must be bound in the enclosing advice or pointcut definition). - Will not match any calls, gets, or sets of static members. -`args(Type or Id, ...)`:: - Picks out each join point where the arguments are instances of the - appropriate type (or type of the identifier if using that form). A `_null_` argument is matched iff the static type of the argument (declared - parameter type or field type) is the same as, or a subtype of, the - specified args type. -`PointcutId(TypePattern or Id, ...)`:: - Picks out each join point that is picked out by the user-defined - pointcut designator named by `_PointcutId_` . -`if(BooleanExpression)`:: - Picks out each join point where the boolean expression evaluates to `_true_` . The boolean expression used can only access static members, - parameters exposed by the enclosing pointcut or advice, and `_thisJoinPoint_` forms. In particular, it cannot call non-static methods on the aspect - or use return values or exceptions exposed by after advice. -`! Pointcut`:: - Picks out each join point that is not picked out by `_Pointcut_` . -`Pointcut0 && Pointcut1`:: - Picks out each join points that is picked out by both `_Pointcut0_` and `_Pointcut1_` . -`Pointcut0 || Pointcut1`:: - Picks out each join point that is picked out by either pointcuts. `_Pointcut0_` or `_Pointcut1_` . -`( Pointcut )`:: - Picks out each join points picked out by `_Pointcut_` . - -==== Pointcut definition - -Pointcuts are defined and named by the programmer with the `pointcut` -declaration. - -[source, java] -.... -pointcut publicIntCall(int i): - call(public * *(int)) && args(i); -.... - -A named pointcut may be defined in either a class or aspect, and is -treated as a member of the class or aspect where it is found. As a -member, it may have an access modifier such as `public` or `private`. - -[source, java] -.... -class C { - pointcut publicCall(int i): - call(public * *(int)) && args(i); -} - -class D { - pointcut myPublicCall(int i): - C.publicCall(i) && within(SomeType); -} -.... - -Pointcuts that are not final may be declared abstract, and defined -without a body. Abstract pointcuts may only be declared within abstract -aspects. - -[source, java] -.... -abstract aspect A { - abstract pointcut publicCall(int i); -} -.... - -In such a case, an extending aspect may override the abstract pointcut. - -[source, java] -.... -aspect B extends A { - pointcut publicCall(int i): call(public Foo.m(int)) && args(i); -} -.... - -For completeness, a pointcut with a declaration may be declared `final`. - -Though named pointcut declarations appear somewhat like method -declarations, and can be overridden in subaspects, they cannot be -overloaded. It is an error for two pointcuts to be named with the same -name in the same class or aspect declaration. - -The scope of a named pointcut is the enclosing class declaration. This -is different than the scope of other members; the scope of other members -is the enclosing class _body_. This means that the following code is -legal: - -[source, java] -.... -aspect B percflow(publicCall()) { - pointcut publicCall(): call(public Foo.m(int)); -} -.... - -==== Context exposure - -Pointcuts have an interface; they expose some parts of the execution -context of the join points they pick out. For example, the PublicIntCall -above exposes the first argument from the receptions of all public unary -integer methods. This context is exposed by providing typed formal -parameters to named pointcuts and advice, like the formal parameters of -a Java method. These formal parameters are bound by name matching. - -On the right-hand side of advice or pointcut declarations, in certain -pointcut designators, a Java identifier is allowed in place of a type or -collection of types. The pointcut designators that allow this are -`this`, `target`, and `args`. In all such cases, using an identifier -rather than a type does two things. First, it selects join points as -based on the type of the formal parameter. So the pointcut - -[source, java] -.... -pointcut intArg(int i): args(i); -.... - -picks out join points where an `int` (or a `byte`, `short`, or `char`; -anything assignable to an `int`) is being passed as an argument. Second, -though, it makes the value of that argument available to the enclosing -advice or pointcut. - -Values can be exposed from named pointcuts as well, so - -[source, java] -.... -pointcut publicCall(int x): call(public *.*(int)) && intArg(x); -pointcut intArg(int i): args(i); -.... - -is a legal way to pick out all calls to public methods accepting an int -argument, and exposing that argument. - -There is one special case for this kind of exposure. Exposing an -argument of type Object will also match primitive typed arguments, and -expose a "boxed" version of the primitive. So, - -[source, java] -.... -pointcut publicCall(): call(public *.*(..)) && args(Object); -.... - -will pick out all unary methods that take, as their only argument, -subtypes of Object (i.e., not primitive types like `int`), but - -[source, java] -.... -pointcut publicCall(Object o): call(public *.*(..)) && args(o); -.... - -will pick out all unary methods that take any argument: And if the -argument was an `int`, then the value passed to advice will be of type -`java.lang.Integer`. - -The "boxing" of the primitive value is based on the _original_ primitive -type. So in the following program - -[source, java] -.... -public class InstanceOf { - public static void main(String[] args) { - doInt(5); - } - - static void doInt(int i) { } -} - -aspect IntToLong { - pointcut el(long l) : - execution(* doInt(..)) && args(l); - - before(Object o) : el(o) { - System.out.println(o.getClass()); - } -} -.... - -The pointcut will match and expose the integer argument, but it will -expose it as an `Integer`, not a `Long`. - -==== Primitive pointcuts - -===== Method-related pointcuts - -AspectJ provides two primitive pointcut designators designed to capture -method call and execution join points. - -* `call( MethodPattern )` -* `execution( MethodPattern )` - -===== Field-related pointcuts - -AspectJ provides two primitive pointcut designators designed to capture -field reference and set join points: - -* `get( FieldPattern )` -* `set( FieldPattern )` - -All set join points are treated as having one argument, the value the -field is being set to, so at a set join point, that value can be -accessed with an `args` pointcut. So an aspect guarding a static integer -variable x declared in type T might be written as - -[source, java] -.... -aspect GuardedX { - static final int MAX_CHANGE = 100; - - before(int newval): set(static int T.x) && args(newval) { - if (Math.abs(newval - T.x) > MAX_CHANGE) - throw new RuntimeException(); - } -} -.... - -===== Object creation-related pointcuts - -AspectJ provides primitive pointcut designators designed to capture the -initializer execution join points of objects. - -* `call( ConstructorPattern )` -* `execution( ConstructorPattern )` -* `initialization( ConstructorPattern )` -* `preinitialization( ConstructorPattern )` - -===== Class initialization-related pointcuts - -AspectJ provides one primitive pointcut designator to pick out static -initializer execution join points. - -* `staticinitialization( TypePattern )` - -===== Exception handler execution-related pointcuts - -AspectJ provides one primitive pointcut designator to capture execution -of exception handlers: - -* `handler( TypePattern )` - -All handler join points are treated as having one argument, the value of -the exception being handled. That value can be accessed with an `args` -pointcut. So an aspect used to put `FooException` objects into some -normal form before they are handled could be written as - -[source, java] -.... -aspect NormalizeFooException { - before(FooException e): handler(FooException) && args(e) { - e.normalize(); - } -} -.... - -===== Advice execution-related pointcuts - -AspectJ provides one primitive pointcut designator to capture execution -of advice - -* `adviceexecution()` - -This can be used, for example, to filter out any join point in the -control flow of advice from a particular aspect. - -[source, java] -.... -aspect TraceStuff { - pointcut myAdvice(): adviceexecution() && within(TraceStuff); - - before(): call(* *(..)) && !cflow(myAdvice) { - // do something - } -} -.... - -===== State-based pointcuts - -Many concerns cut across the dynamic times when an object of a -particular type is executing, being operated on, or being passed around. -AspectJ provides primitive pointcuts that capture join points at these -times. These pointcuts use the dynamic types of their objects to pick -out join points. They may also be used to expose the objects used for -discrimination. - -* `this( Type or Id )` -* `target( Type or Id )` - -The `this` pointcut picks out each join point where the currently -executing object (the object bound to `this`) is an instance of a -particular type. The `target` pointcut picks out each join point where -the target object (the object on which a method is called or a field is -accessed) is an instance of a particular type. Note that `target` should -be understood to be the object the current join point is transfering -control to. This means that the target object is the same as the current -object at a method execution join point, for example, but may be -different at a method call join point. - -* `args( Type or Id or "..", ...)` - -The args pointcut picks out each join point where the arguments are -instances of some types. Each element in the comma-separated list is one -of four things. If it is a type name, then the argument in that position -must be an instance of that type. If it is an identifier, then that -identifier must be bound in the enclosing advice or pointcut -declaration, and so the argument in that position must be an instance of -the type of the identifier (or of any type if the identifier is typed to -Object). If it is the `*` wildcard, then any argument will match, and if -it is the special wildcard `..`, then any number of arguments will -match, just like in signature patterns. So the pointcut - -[source, java] -.... -args(int, .., String) -.... - -will pick out all join points where the first argument is an `int` and -the last is a `String`. - -===== Control flow-based pointcuts - -Some concerns cut across the control flow of the program. The `cflow` -and `cflowbelow` primitive pointcut designators capture join points -based on control flow. - -* `cflow( Pointcut )` -* `cflowbelow( Pointcut )` - -The `cflow` pointcut picks out all join points that occur between entry -and exit of each join point `P` picked out by `Pointcut`, including `P` -itself. Hence, it picks out the join points _in_ the control flow of the -join points picked out by `Pointcut`. - -The `cflowbelow` pointcut picks out all join points that occur between -entry and exit of each join point `P` picked out by `Pointcut`, but not -including `P` itself. Hence, it picks out the join points _below_ the -control flow of the join points picked out by `Pointcut`. - -====== Context exposure from control flows - -The `cflow` and `cflowbelow` pointcuts may expose context state through -enclosed `this`, `target`, and `args` pointcuts. - -Anytime such state is accessed, it is accessed through the _most recent_ -control flow that matched. So the "current arg" that would be printed by -the following program is zero, even though it is in many control flows. - -[source, java] -.... -class Test { - public static void main(String[] args) { - fact(5); - } - static int fact(int x) { - if (x == 0) { - System.err.println("bottoming out"); - return 1; - } - else return x * fact(x - 1); - } -} - -aspect A { - pointcut entry(int i): call(int fact(int)) && args(i); - pointcut writing(): call(void println(String)) && ! within(A); - - before(int i): writing() && cflow(entry(i)) { - System.err.println("Current arg is " + i); - } -} -.... - -It is an error to expose such state through _negated_ control flow -pointcuts, such as within `!cflowbelow(P)`. - -===== Program text-based pointcuts - -While many concerns cut across the runtime structure of the program, -some must deal with the lexical structure. AspectJ allows aspects to -pick out join points based on where their associated code is defined. - -* `within( TypePattern )` -* `withincode( MethodPattern )` -* `withincode( ConstructorPattern )` - -The `within` pointcut picks out each join point where the code executing -is defined in the declaration of one of the types in `TypePattern`. This -includes the class initialization, object initialization, and method and -constructor execution join points for the type, as well as any join -points associated with the statements and expressions of the type. It -also includes any join points that are associated with code in a type's -nested types, and that type's default constructor, if there is one. - -The `withincode` pointcuts picks out each join point where the code -executing is defined in the declaration of a particular method or -constructor. This includes the method or constructor execution join -point as well as any join points associated with the statements and -expressions of the method or constructor. It also includes any join -points that are associated with code in a method or constructor's local -or anonymous types. - -===== Expression-based pointcuts - -* `if( BooleanExpression )` - -The if pointcut picks out join points based on a dynamic property. its -syntax takes an expression, which must evaluate to a boolean true or -false. Within this expression, the `thisJoinPoint` object is available. -So one (extremely inefficient) way of picking out all call join points -would be to use the pointcut - -[source, java] -.... -if(thisJoinPoint.getKind().equals("call")) -.... - -Note that the order of evaluation for pointcut expression components at -a join point is undefined. Writing `if` pointcuts that have side-effects -is considered bad style and may also lead to potentially confusing or -even changing behavior with regard to when or if the test code will run. - -==== Signatures - -One very important property of a join point is its signature, which is -used by many of AspectJ's pointcut designators to select particular join -points. - -===== Methods - -Join points associated with methods typically have method signatures, -consisting of a method name, parameter types, return type, the types of -the declared (checked) exceptions, and some type that the method could -be called on (below called the "qualifying type"). - -At a method call join point, the signature is a method signature whose -qualifying type is the static type used to _access_ the method. This -means that the signature for the join point created from the call -`((Integer)i).toString()` is different than that for the call -`((Object)i).toString()`, even if `i` is the same variable. - -At a method execution join point, the signature is a method signature -whose qualifying type is the declaring type of the method. - -===== Fields - -Join points associated with fields typically have field signatures, -consisting of a field name and a field type. A field reference join -point has such a signature, and no parameters. A field set join point -has such a signature, but has a has a single parameter whose type is the -same as the field type. - -===== Constructors - -Join points associated with constructors typically have constructor -signatures, consisting of a parameter types, the types of the declared -(checked) exceptions, and the declaring type. - -At a constructor call join point, the signature is the constructor -signature of the called constructor. At a constructor execution join -point, the signature is the constructor signature of the currently -executing constructor. - -At object initialization and pre-initialization join points, the -signature is the constructor signature for the constructor that started -this initialization: the first constructor entered during this type's -initialization of this object. - -===== Others - -At a handler execution join point, the signature is composed of the -exception type that the handler handles. - -At an advice execution join point, the signature is composed of the -aspect type, the parameter types of the advice, the return type (void -for all but around advice) and the types of the declared (checked) -exceptions. - -==== Matching - -The `withincode`, `call`, `execution`, `get`, and `set` primitive -pointcut designators all use signature patterns to determine the join -points they describe. A signature pattern is an abstract description of -one or more join-point signatures. Signature patterns are intended to -match very closely the same kind of things one would write when -declaring individual members and constructors. - -Method declarations in Java include method names, method parameters, -return types, modifiers like static or private, and throws clauses, -while constructor declarations omit the return type and replace the -method name with the class name. The start of a particular method -declaration, in class `Test`, for example, might be - -[source, java] -.... -class C { - public final void foo() throws ArrayOutOfBoundsException { ... } -} -.... - -In AspectJ, method signature patterns have all these, but most elements -can be replaced by wildcards. So - -[source, java] -.... -call(public final void C.foo() throws ArrayOutOfBoundsException) -.... - -picks out call join points to that method, and the pointcut - -[source, java] -.... -call(public final void *.*() throws ArrayOutOfBoundsException) -.... - -picks out all call join points to methods, regardless of their name name -or which class they are defined on, so long as they take no arguments, -return no value, are both `public` and `final`, and are declared to -throw ``ArrayOutOfBoundsException``s. - -The defining type name, if not present, defaults to *, so another way of -writing that pointcut would be - -[source, java] -.... -call(public final void *() throws ArrayOutOfBoundsException) -.... - -The wildcard `..` indicates zero or more parameters, so - -[source, java] -.... -execution(void m(..)) -.... - -picks out execution join points for void methods named `m`, of any -number of arguments, while - -[source, java] -.... -execution(void m(.., int)) -.... - -picks out execution join points for void methods named `m` whose last -parameter is of type `int`. - -The modifiers also form part of the signature pattern. If an AspectJ -signature pattern should match methods without a particular modifier, -such as all non-public methods, the appropriate modifier should be -negated with the `!` operator. So, - -[source, java] -.... -withincode(!public void foo()) -.... - -picks out all join points associated with code in null non-public void -methods named `foo`, while - -[source, java] -.... -withincode(void foo()) -.... - -picks out all join points associated with code in null void methods -named `foo`, regardless of access modifier. - -Method names may contain the * wildcard, indicating any number of -characters in the method name. So - -[source, java] -.... -call(int *()) -.... - -picks out all call join points to `int` methods regardless of name, but - -[source, java] -.... -call(int get*()) -.... - -picks out all call join points to `int` methods where the method name -starts with the characters "get". - -AspectJ uses the `new` keyword for constructor signature patterns rather -than using a particular class name. So the execution join points of -private null constructor of a class `C` defined to throw an -`ArithmeticException` can be picked out with - -[source, java] -.... -execution(private C.new() throws ArithmeticException) -.... - -===== Matching based on the declaring type - -The signature-matching pointcuts all specify a declaring type, but the -meaning varies slightly for each join point signature, in line with Java -semantics. - -When matching for pointcuts `withincode`, `get`, and `set`, the -declaring type is the class that contains the declaration. - -When matching method-call join points, the declaring type is the static -type used to access the method. A common mistake is to specify a -declaring type for the `call` pointcut that is a subtype of the -originally-declaring type. For example, given the class - -[source, java] -.... -class Service implements Runnable { - public void run() { ... } -} -.... - -the following pointcut - -[source, java] -.... -call(void Service.run()) -.... - -would fail to pick out the join point for the code - -[source, java] -.... -((Runnable) new Service()).run(); -.... - -Specifying the originally-declaring type is correct, but would pick out -any such call (here, calls to the `run()` method of any `Runnable`). In -this situation, consider instead picking out the target type: - -[source, java] -.... -call(void run()) && target(Service) -.... - -When matching method-execution join points, if the execution pointcut -method signature specifies a declaring type, the pointcut will only -match methods declared in that type, or methods that override methods -declared in or inherited by that type. So the pointcut - -[source, java] -.... -execution(public void Middle.*()) -.... - -picks out all method executions for public methods returning void and -having no arguments that are either declared in, or inherited by, -`Middle`, even if those methods are overridden in a subclass of `Middle`. So -the pointcut would pick out the method-execution join point for `Sub.m()` -in this code: - -[source, java] -.... -class Super { - protected void m() { /*...*/ } -} - -class Middle extends Super {} - -class Sub extends Middle { - public void m() { /*...*/ } -} -.... - -===== Matching based on the `throws` clause - -Type patterns may be used to pick out methods and constructors based on -their `throws` clauses. This allows the following two kinds of extremely -wildcarded pointcuts: - -[source, java] -.... -pointcut throwsMathlike(): - // each call to a method with a throws clause containing at least - // one exception exception with "Math" in its name. - call(* *(..) throws *..*Math*); - -pointcut doesNotThrowMathlike(): - // each call to a method with a throws clause containing no - // exceptions with "Math" in its name. - call(* *(..) throws !*..*Math*); -.... - -A `ThrowsClausePattern` is a comma-separated list of ``ThrowsClausePatternItem``s, where - -[source, text] -.... -ThrowsClausePatternItem := [ ! ] TypeNamePattern -.... - -A `ThrowsClausePattern` matches the `throws` clause of any code member -signature. To match, each `ThrowsClausePatternItem` must match the -`throws` clause of the member in question. If any item doesn't match, then -the whole pattern doesn't match. - -If a `ThrowsClausePatternItem` begins with `!`, then it matches a -particular `throws` clause if and only if _none_ of the types named in the -`throws` clause is matched by the `TypeNamePattern`. - -If a `ThrowsClausePatternItem` does not begin with `!`, then it matches -a throws clause if and only if _any_ of the types named in the `throws` -clause is matched by the `TypeNamePattern`. - -The rule for `!` matching has one potentially surprising property, in -that these two pointcuts - -. `call(* *(..) throws !IOException)` -. `call(* *(..) throws (!IOException))` - -will match differently on calls to - -[source, java] -.... -void m() throws RuntimeException, IOException {} -.... - -[1] will *not* match the method `m()`, because ``m``'s throws clause -declares that it `throws IOException`. - -[2] *will* match the method `m()`, because ``m``'s throws clause declares that -it throws some exception which does not match `IOException`, i.e. `RuntimeException`. - -==== Type patterns - -Type patterns are a way to pick out collections of types and use them in -places where you would otherwise use only one type. The rules for using -type patterns are simple. - -===== Exact type pattern - -First, all type names are also type patterns. So `Object`, -`java.util.HashMap`, `Map.Entry`, `int` are all type patterns. - -If a type pattern is an exact type - if it doesn't include a wildcard - -then the matching works just like normal type lookup in Java: - -* Patterns that have the same names as primitive types (like `int`) match those - primitive types. -* Patterns that are qualified by package names (like `java.util.HashMap`) match - types in other packages. -* Patterns that are not qualified (like `HashMap`) match types that are resolved - by Java's normal scope rules. So, for example, `HashMap` might match a package-level - type in the same package or a type that have been imported with Java's `import` - form. But it would not match `java.util.HashMap` unless the aspect were in `java.util` - or the type had been imported. - -So exact type patterns match based on usual Java scope rules. - -===== Type name patterns - -There is a special type name, `\*`, which is also a type pattern. `*` picks -out all types, including primitive types. So - -[source, java] -.... -call(void foo(*)) -.... - -picks out all call join points to void methods named foo, taking one -argument of any type. - -Type names that contain the two wildcards `\*` and `..` are also type -patterns. The `*` wildcard matches zero or more characters characters -except for `.`, so it can be used when types have a certain naming -convention. So - -[source, java] -.... -handler(java.util.*Map) -.... - -picks out the types `java.util.Map` and `java.util.java.util.HashMap`, among -others, and - -[source, java] -.... -handler(java.util.*) -.... - -picks out all types that start with `java.util.` and don't have any -more ``.``s, that is, the types in the `java.util` package, but not inner -types (such as `java.util.Map.Entry`). - -The `..` wildcard matches any sequence of characters that start and -end with a `.`, so it can be used to pick out all types in any -subpackage, or all inner types. So - -[source, java] -.... -within(com.xerox..*) -.... - -picks out all join points where the code is in any declaration of a type -whose name begins with `com.xerox.`. - -Type patterns with wildcards do not depend on Java's usual scope rules - -they match against all types available to the weaver, not just those -that are imported into an Aspect's declaring file. - -===== Subtype patterns - -It is possible to pick out all subtypes of a type (or a collection of -types) with the `+` wildcard. The `+` wildcard follows immediately a -type name pattern. So, while - -[source, java] -.... -call(Foo.new()) -.... - -picks out all constructor call join points where an instance of exactly -type `Foo` is constructed, - -[source, java] -.... -call(Foo+.new()) -.... - -picks out all constructor call join points where an instance of any -subtype of `Foo` (including `Foo` itself) is constructed, and the unlikely - -[source, java] -.... -call(*Handler+.new()) -.... - -picks out all constructor call join points where an instance of any -subtype of any type whose name ends in `Handler` is constructed. - -===== Array type patterns - -A type name pattern or subtype pattern can be followed by one or more -sets of square brackets to make array type patterns. So `Object[]` is an -array type pattern, and so is `com.xerox..*[][]`, and so is `Object+[]`. - -===== Type patterns - -Type patterns are built up out of type name patterns, subtype patterns, -and array type patterns, and constructed with boolean operators `&&`, -`||`, and `!`. So - -[source, java] -.... -staticinitialization(Foo || Bar) -.... - -picks out the static initializer execution join points of either `Foo` or -`Bar`, and - -[source, java] -.... -call((Foo+ && ! Foo).new(..)) -.... - -picks out the constructor call join points when a subtype of `Foo`, but -not `Foo` itself, is constructed. - -==== Pattern Summary - -Here is a summary of the pattern syntax used in AspectJ: - -[source, text] -.... -MethodPattern = - [ModifiersPattern] TypePattern - [TypePattern . ] IdPattern (TypePattern | ".." , ... ) - [ throws ThrowsPattern ] -ConstructorPattern = - [ModifiersPattern ] - [TypePattern . ] new (TypePattern | ".." , ...) - [ throws ThrowsPattern ] -FieldPattern = - [ModifiersPattern] TypePattern [TypePattern . ] IdPattern -ThrowsPattern = - [ ! ] TypePattern , ... -TypePattern = - IdPattern [ + ] [ [] ... ] - | ! TypePattern - | TypePattern && TypePattern - | TypePattern || TypePattern - | ( TypePattern ) -IdPattern = - Sequence of characters, possibly with special * and .. wildcards -ModifiersPattern = - [ ! ] JavaModifier ... -.... - -[[semantics-advice]] -=== Advice - -Each piece of advice is of the form - -[source, text] -.... -[ strictfp ] AdviceSpec [ throws TypeList ] : Pointcut { Body } -.... - -where `AdviceSpec` is one of - -* `before( Formals )` -* `after( Formals ) returning [ ( Formal ) ]` -* `after( Formals ) throwing [ ( Formal ) ]` -* `after( Formals )` -* `Type around( Formals )` - -and where `Formal` refers to a variable binding like those used for -method parameters, of the form `Type` `Variable-Name`, and `Formals` -refers to a comma-delimited list of `Formal`. - -Advice defines crosscutting behavior. It is defined in terms of -pointcuts. The code of a piece of advice runs at every join point picked -out by its pointcut. Exactly how the code runs depends on the kind of -advice. - -AspectJ supports three kinds of advice. The kind of advice determines -how it interacts with the join points it is defined over. Thus AspectJ -divides advice into that which runs *before* its join points, that which -runs *after* its join points, and that which runs *in place of (or -"around")* its join points. - -While `before` advice is relatively unproblematic, there can be three -interpretations of `after` advice: After the execution of a join point -completes normally, after it throws an exception, or after it does -either one. AspectJ allows `after` advice for any of these situations: - -[source, java] -.... -aspect A { - pointcut publicCall(): call(public Object *(..)); - - after() returning (Object o): publicCall() { - System.out.println("Returned normally with " + o); - } - - after() throwing (Exception e): publicCall() { - System.out.println("Threw an exception: " + e); - } - - after(): publicCall(){ - System.out.println("Returned or threw an Exception"); - } -} -.... - -`after returning` advice may not care about its returned object, in which -case it may be written - -[source, java] -.... -after() returning: call(public Object *(..)) { - System.out.println("Returned normally"); -} -.... - -If `after returning` does expose its returned object, then the type of the -parameter is considered to be an `instanceof`-like constraint on the -advice: it will run only when the return value is of the appropriate -type. - -A value is of the appropriate type if it would be assignable to a -variable of that type, in the Java sense. That is, a `byte` value is -assignable to a `short` parameter but not vice-versa, an `int` is -assignable to a `float` parameter, `boolean` values are only assignable -to `boolean` parameters, and reference types work by `instanceof`. - -There are two special cases: If the exposed value is typed to `Object`, -then the advice is not constrained by that type: the actual return value -is converted to an object type for the body of the advice: `int` values -are represented as `java.lang.Integer` objects, etc, and no value (from -`void` methods, for example) is represented as `null`. - -Secondly, the `null` value is assignable to a parameter `T` if the join -point _could_ return something of type `T`. - -`around` advice runs in place of the join point it operates over, rather -than before or after it. Because `around` is allowed to return a value, it -must be declared with a return type, like a method. - -Thus, a simple use of `around` advice is to make a particular method -constant: - -[source, java] -.... -aspect A { - int around(): call(int C.foo()) { - return 3; - } -} -.... - -Within the body of `around` advice, though, the computation of the -original join point can be executed with the special syntax - -[source, java] -.... -proceed( ... ) -.... - -The `proceed` form takes as arguments the context exposed by the around's -pointcut, and returns whatever the around is declared to return. So the -following around advice will double the second argument to `foo` -whenever it is called, and then halve its result: - -[source, java] -.... -aspect A { - int around(int i): call(int C.foo(Object, int)) && args(i) { - int newi = proceed(i*2) - return newi/2; - } -} -.... - -If the return value of `around` advice is typed to `Object`, then the -result of proceed is converted to an object representation, even if it -is originally a primitive value. And when the advice returns an `Object` -value, that value is converted back to whatever representation it was -originally. So another way to write the doubling and halving advice is: - -[source, java] -.... -aspect A { - Object around(int i): call(int C.foo(Object, int)) && args(i) { - Integer newi = (Integer) proceed(i*2) - return new Integer(newi.intValue() / 2); - } -} -.... - -Any occurence of `proceed(..)` within the body of around advice is -treated as the special `proceed` form (even if the aspect defines a method -named `proceed`), unless a target other than the aspect instance is -specified as the recipient of the call. For example, in the following -program the first call to `proceed` will be treated as a method call to -the `ICanProceed` instance, whereas the second call to `proceed` is -treated as the special `proceed` form. - -[source, java] -.... -aspect A { - Object around(ICanProceed canProceed) : execution(* *(..)) && this(canProceed) { - canProceed.proceed(); // a method call - return proceed(canProceed); // the special proceed form - } - - private Object proceed(ICanProceed canProceed) { - // this method cannot be called from inside the body of around advice - // in the aspect - } -} -.... - -In all kinds of advice, the parameters of the advice behave exactly like -method parameters. In particular, assigning to any parameter affects -only the value of the parameter, not the value that it came from. This -means that - -[source, java] -.... -aspect A { - after() returning (int i): call(int C.foo()) { - i = i * 2; - } -} -.... - -will _not_ double the returned value of the advice. Rather, it will -double the local parameter. Changing the values of parameters or return -values of join points can be done by using `around` advice. - -With `proceed(..)` it is possible to change the values used by -less-precedent advice and the underlying join point by supplying -different values for the variables. For example, this aspect replaces -the string bound to `s` in the named pointcut `privateData`: - -[source, java] -.... -aspect A { - Object around(String s): MyPointcuts.privateData(s) { - return proceed("private data"); - } -} -.... - -If you replace an argument to `proceed(..)`, you can cause a -`ClassCastException` at runtime when the argument refers to a supertype -of the actual type and you do not supply a reference of the actual type. -In the following aspect, the around advice replaces the declared target -`List` with an `ArrayList`. This is valid code at compile-time since the -types match. - -[source, java] -.... -import java.util.*; - -aspect A { - Object around(List list): call(* List+.*()) && target(list) { - return proceed(new ArrayList()); - } -} -.... - -But imagine a simple program where the actual target is `LinkedList`. In -this case, the advice would cause a `ClassCastException` at runtime, and -`peek()` is not declared in `ArrayList`. - -[source, java] -.... -public class Test { - public static void main(String[] args) { - new LinkedList().peek(); - } -} -.... - -The `ClassCastException` can occur even in situations where it appears -to be unnecessary, e.g., if the program is changed to call `size()`, -declared in `List`: - -[source, java] -.... -public class Test { - public static void main(String[] args) { - new LinkedList().size(); - } -} -.... - -There will still be a `ClassCastException` because it is impossible to -prove that there won't be a runtime binary-compatible change in the -hierarchy of `LinkedList` or some other advice on the join point that -requires a `LinkedList`. - -==== Advice modifiers - -The `strictfp` modifier is the only modifier allowed on advice, and it -has the effect of making all floating-point expressions within the -advice be FP-strict. - -==== Advice and checked exceptions - -An advice declaration must include a `throws` clause listing the checked -exceptions the body may throw. This list of checked exceptions must be -compatible with each target join point of the advice, or an error is -signalled by the compiler. - -For example, in the following declarations: - -[source, java] -.... -import java.io.FileNotFoundException; - -class C { - int i; - int getI() { return i; } -} - -aspect A { - before(): get(int C.i) { - throw new FileNotFoundException(); - } - - before() throws FileNotFoundException: get(int C.i) { - throw new FileNotFoundException(); - } -} -.... - -both pieces of advice are illegal. The first because the body throws an -undeclared checked exception, and the second because field get join -points cannot throw ``FileNotFoundException``s. - -The exceptions that each kind of join point in AspectJ may throw are: - -method call and execution:: - the checked exceptions declared by the target method's `throws` clause. -constructor call and execution:: - the checked exceptions declared by the target constructor's `throws` clause. -field get and set:: - no checked exceptions can be thrown from these join points. -exception handler execution:: - the exceptions that can be thrown by the target exception handler. -static initializer execution:: - no checked exceptions can be thrown from these join points. -pre-initialization and initialization:: - any exception that is in the `throws` clause of all constructors of the initialized class. -advice execution:: - any exception that is in the `throws` clause of the advice. - -==== Advice precedence - -Multiple pieces of advice may apply to the same join point. In such -cases, the resolution order of the advice is based on advice precedence. - -===== Determining precedence - -There are a number of rules that determine whether a particular piece of -advice has precedence over another when they advise the same join point. - -If the two pieces of advice are defined in different aspects, then there -are three cases: - -* If aspect `A` is matched earlier than aspect `B` in some `declare precedence` - form, then all advice in concrete aspect `A` has precedence over all - advice in concrete aspect `B` when they are on the same join point. -* Otherwise, if aspect `A` is a subaspect of aspect `B`, then all advice - defined in `A` has precedence over all advice defined in `B`. So, unless - otherwise specified with `declare precedence`, advice in a subaspect has - precedence over advice in a superaspect. -* Otherwise, if two pieces of advice are defined in two different - aspects, it is undefined which one has precedence. - -If the two pieces of advice are defined in the same aspect, then there -are two cases: - -* If either are `after` advice, then the one that appears later in the aspect has precedence - over the one that appears earlier. -* Otherwise, then the one that appears earlier in the aspect has - precedence over the one that appears later. - -These rules can lead to circularity, such as - -[source, java] -.... -aspect A { - before(): execution(void main(String[] args)) {} - after(): execution(void main(String[] args)) {} - before(): execution(void main(String[] args)) {} -} -.... - -such circularities will result in errors signalled by the compiler. - -===== Effects of precedence - -At a particular join point, advice is ordered by precedence. - -A piece of `around` advice controls whether advice of lower precedence -will run by calling `proceed`. The call to `proceed` will run the advice -with next precedence, or the computation under the join point if there -is no further advice. - -A piece of `before` advice can prevent advice of lower precedence from -running by throwing an exception. If it returns normally, however, then -the advice of the next precedence, or the computation under the join -pint if there is no further advice, will run. - -Running `after returning` advice will run the advice of next precedence, -or the computation under the join point if there is no further advice. -Then, if that computation returned normally, the body of the advice will -run. - -Running `after throwing` advice will run the advice of next precedence, -or the computation under the join point if there is no further advice. -Then, if that computation threw an exception of an appropriate type, the -body of the advice will run. - -Running `after` advice will run the advice of next precedence, or the -computation under the join point if there is no further advice. Then the -body of the advice will run. - -==== Reflective access to the join point - -Three special variables are visible within bodies of advice and within -`if()` pointcut expressions: `thisJoinPoint`, `thisJoinPointStaticPart`, -and `thisEnclosingJoinPointStaticPart`. Each is bound to an object that -encapsulates some of the context of the advice's current or enclosing -join point. These variables exist because some pointcuts may pick out -very large collections of join points. For example, the pointcut - -[source, java] -.... -pointcut publicCall(): call(public * *(..)); -.... - -picks out calls to many methods. Yet the body of advice over this -pointcut may wish to have access to the method name or parameters of a -particular join point. - -* `thisJoinPoint` is bound to a complete join point object. - -* `thisJoinPointStaticPart` is bound to a part of the join point object - that includes less information, but for which no memory allocation is - required on each execution of the advice. It is equivalent to - `thisJoinPoint.getStaticPart()`. - -* `thisEnclosingJoinPointStaticPart` is bound to the static part of the - join point enclosing the current join point. Only the static part of - this enclosing join point is available through this mechanism. - -Standard Java reflection uses objects from the `java.lang.reflect` -hierarchy to build up its reflective objects. Similarly, AspectJ join -point objects have types in a type hierarchy. The type of objects bound -to `thisJoinPoint` is `org.aspectj.lang.JoinPoint`, while -`thisStaticJoinPoint` is bound to objects of interface type -`org.aspectj.lang.JoinPoint.StaticPart`. - -[[semantics-declare]] -=== Static crosscutting - -Advice declarations change the behavior of classes they crosscut, but do -not change their static type structure. For crosscutting concerns that -do operate over the static structure of type hierarchies, AspectJ -provides inter-type member declarations and other `declare` forms. - -==== Inter-type member declarations - -AspectJ allows the declaration of members by aspects that are associated -with other types. - -An inter-type method declaration looks like - -* `[ Modifiers ] Type OnType . Id ( Formals ) [ ThrowsClause ] { Body }` -* `abstract [ Modifiers ] Type OnType . Id ( Formals ) [ ThrowsClause ] ;` - -The effect of such a declaration is to make `OnType` support the new -method. Even if `OnType` is an interface. Even if the method is neither -public nor abstract. So the following is legal AspectJ code: - -[source, java] -.... -interface Iface {} - -aspect A { - private void Iface.m() { - System.err.println("I'm a private method on an interface"); - } - - void worksOnI(Iface iface) { - // calling a private method on an interface - iface.m(); - } -} -.... - -An inter-type constructor declaration looks like - -* `[ Modifiers ] OnType . new ( Formals ) [ ThrowsClause ] { Body }` - -The effect of such a declaration is to make `OnType` support the new -constructor. It is an error for `OnType` to be an interface. - -Inter-type declared constructors cannot be used to assign a value to a -final variable declared in `OnType`. This limitation significantly -increases the ability to both understand and compile the `OnType` class -and the declaring aspect separately. - -Note that in the Java language, classes that define no constructors have -an implicit no-argument constructor that just calls `super()`. This -means that attempting to declare a no-argument inter-type constructor on -such a class may result in a conflict, even though it _looks_ like no -constructor is defined. - -An inter-type field declaration looks like one of - -* `[ Modifiers ] Type OnType . Id = Expression ;` -* `[ Modifiers ] Type OnType . Id ;` - -The effect of such a declaration is to make `OnType` support the new -field. Even if `OnType` is an interface. Even if the field is neither -public, nor static, nor final. - -The initializer, if any, of an inter-type field declaration runs before -the class-local initializers defined in its target class. - -Any occurrence of the identifier `this` in the body of an inter-type -constructor or method declaration, or in the initializer of an -inter-type field declaration, refers to the `OnType` object rather than -to the aspect type; it is an error to access `this` in such a position -from a `static` inter-type member declaration. - -==== Access modifiers - -Inter-type member declarations may be `public` or `private`, or have default -(package-protected) visibility. AspectJ does not provide protected -inter-type members. - -The access modifier applies in relation to the aspect, not in relation -to the target type. So a private inter-type member is visible only from -code that is defined within the declaring aspect. A default-visibility -inter-type member is visible only from code that is defined within the -declaring aspect's package. - -Note that a declaring a private inter-type method (which AspectJ -supports) is very different from inserting a private method declaration -into another class. The former allows access only from the declaring -aspect, while the latter would allow access only from the target type. -Java serialization, for example, uses the presense of a private method -`void writeObject(ObjectOutputStream)` for the implementation of -`java.io.Serializable`. A private inter-type declaration of that method -would not fulfill this requirement, since it would be private to the -aspect, not private to the target type. - -The access modifier of abstract inter-type methods has one constraint: -It is illegal to declare an abstract non-public inter-type method on a -public interface. This is illegal because it would say that a public -interface has a constraint that only non-public implementors must -fulfill. This would not be compatible with Java's type system. - -==== Conflicts - -Inter-type declarations raise the possibility of conflicts among locally -declared members and inter-type members. For example, assuming -`otherPackage` is not the package containing the aspect `A`, the code - -[source, java] -.... -aspect A { - private Registry otherPackage.onType.r; - - public void otherPackage.onType.register(Registry r) { - r.register(this); - this.r = r; - } -} -.... - -declares that `onType` in `otherPackage` has a field `r`. This field, -however, is only accessible from the code inside of aspect `A`. The -aspect also declares that `onType` has a method "`register`", but makes -this method accessible from everywhere. - -If `onType` already defines a private or package-protected field `r`, -there is no conflict: The aspect cannot see such a field, and no code in -`otherPackage` can see the inter-type `r`. - -If `onType` defines a public field `r`, there is a conflict: The -expression - -[source, java] -.... -this.r = r -.... - -is an error, since it is ambiguous whether the private inter-type `r` -or the public locally-defined `r` should be used. - -If `onType` defines a method `register(Registry)` there is a conflict, -since it would be ambiguous to any code that could see such a defined -method which `register(Registry)` method was applicable. - -Conflicts are resolved as much as possible as per Java's conflict -resolution rules: - -* A subclass can inherit multiple fields from its superclasses, all with the - same name and type. However, it is an error to have an ambiguous reference - to a field. -* A subclass can only inherit multiple methods with the same name and argument - types from its superclasses if only zero or one of them is concrete (i.e., all - but one is abstract, or all are abstract). - -Given a potential conflict between inter-type member declarations in -different aspects, if one aspect has precedence over the other its -declaration will take effect without any conflict notice from compiler. -This is true both when the precedence is declared explicitly with -`declare precedence` as well as when when sub-aspects implicitly have -precedence over their super-aspect. - -==== Extension and Implementation - -An aspect may change the inheritance hierarchy of a system by changing -the superclass of a type or adding a superinterface onto a type, with -the `declare parents` form. - -* `declare parents: TypePattern extends Type ;` -* `declare parents: TypePattern implements TypeList ;` - -For example, if an aspect wished to make a particular class runnable, it -might define appropriate inter-type `void - run()` method, but it should also declare that the class -fulfills the `Runnable` interface. In order to implement the methods in -the `Runnable` interface, the inter-type `run()` method must be public: - -[source, java] -.... -aspect A { - declare parents: SomeClass implements Runnable; - - public void SomeClass.run() { ... } -} -.... - -==== Interfaces with members - -Through the use of inter-type members, interfaces may now carry -(non-public-static-final) fields and (non-public-abstract) methods that -classes can inherit. Conflicts may occur from ambiguously inheriting -members from a superclass and multiple superinterfaces. - -Because interfaces may carry non-static initializers, each interface -behaves as if it has a zero-argument constructor containing its -initializers. The order of super-interface instantiation is observable. -We fix this order with the following properties: A supertype is -initialized before a subtype, initialized code runs only once, and the -initializers for a type's superclass are run before the initializers for -its superinterfaces. Consider the following hierarchy where {`Object`, -`C`, `D`, `E`} are classes, {`M`, `N`, `O`, `P`, `Q`} are interfaces. - -[source, text] -.... -Object M O - \ / \ / - C N Q - \ / / - D P - \ / - E -.... - -when a new `E` is instantiated, the initializers run in this order: - -[source, text] -.... -Object M C O N D Q P E -.... - -==== Warnings and Errors - -An aspect may specify that a particular join point should never be -reached. - -* `declare error: Pointcut : String ;` -* `declare warning: Pointcut : String ;` - -If the compiler determines that a join point in `Pointcut` could -possibly be reached, then it will signal either an error or warning, as -declared, using the `String` for its message. - -==== Softened exceptions - -An aspect may specify that a particular kind of exception, if thrown at -a join point, should bypass Java's usual static exception checking -system and instead be thrown as a `org.aspectj.lang.SoftException`, -which is subtype of `RuntimeException` and thus does not need to be -declared. - -* `declare soft: Type : Pointcut ;` - -For example, the aspect - -[source, java] -.... -aspect A { - declare soft: Exception: execution(void main(String[] args)); -} -.... - -Would, at the execution join point, catch any `Exception` and rethrow a -`org.aspectj.lang.SoftException` containing original exception. - -This is similar to what the following advice would do - -[source, java] -.... -aspect A { - void around() execution(void main(String[] args)) { - try { proceed(); } - catch (Exception e) { - throw new org.aspectj.lang.SoftException(e); - } - } -} -.... - -except, in addition to wrapping the exception, it also affects Java's -static exception checking mechanism. - -Like advice, the declare soft form has no effect in an abstract aspect -that is not extended by a concreate aspect. So the following code will -not compile unless it is compiled with an extending concrete aspect: - -[source, java] -.... -abstract aspect A { - abstract pointcut softeningPC(); - - before() : softeningPC() { - Class.forName("FooClass"); // error: uncaught ClassNotFoundException - } - - declare soft : ClassNotFoundException : call(* Class.*(..)); -} -.... - -[[advice-precedence-cross]] -==== Advice Precedence - -An aspect may declare a precedence relationship between concrete aspects -with the `declare precedence` form: - -* `declare precedence : TypePatternList ;` - -This signifies that if any join point has advice from two concrete -aspects matched by some pattern in `TypePatternList`, then the -precedence of the advice will be the order of in the list. - -In `TypePatternList`, the wildcard `*` can appear at most once, and it -means "any type not matched by any other pattern in the list". - -For example, the constraints that (1) aspects that have Security as part -of their name should have precedence over all other aspects, and (2) the -Logging aspect (and any aspect that extends it) should have precedence -over all non-security aspects, can be expressed by: - -[source, java] -.... -declare precedence: *..*Security*, Logging+, *; -.... - -For another example, the `CountEntry` aspect might want to count the entry -to methods in the current package accepting a Type object as its first -argument. However, it should count all entries, even those that the -aspect `DisallowNulls` causes to throw exceptions. This can be -accomplished by stating that `CountEntry` has precedence over -`DisallowNulls`. This declaration could be in either aspect, or in -another, ordering aspect: - -[source, java] -.... -aspect Ordering { - declare precedence: CountEntry, DisallowNulls; -} - -aspect DisallowNulls { - pointcut allTypeMethods(Type obj): call(* *(..)) && args(obj, ..); - before(Type obj): allTypeMethods(obj) { - if (obj == null) throw new RuntimeException(); - } -} - -aspect CountEntry { - pointcut allTypeMethods(Type obj): call(* *(..)) && args(obj, ..); - static int count = 0; - before(): allTypeMethods(Type) { - count++; - } -} -.... - -===== Various cycles - -It is an error for any aspect to be matched by more than one TypePattern -in a single decare precedence, so: - -[source, java] -.... -declare precedence: A, B, A ; // error -.... - -However, multiple declare precedence forms may legally have this kind of -circularity. For example, each of these declare precedence is perfectly -legal: - -[source, java] -.... -declare precedence: B, A; -declare precedence: A, B; -.... - -And a system in which both constraints are active may also be legal, so -long as advice from `A` and `B` don't share a join point. So this is an -idiom that can be used to enforce that `A` and `B` are strongly independent. - -===== Applies to concrete aspects - -Consider the following library aspects: - -[source, java] -.... -abstract aspect Logging { - abstract pointcut logged(); - - before(): logged() { - System.err.println("thisJoinPoint: " + thisJoinPoint); - } -} - -abstract aspect MyProfiling { - abstract pointcut profiled(); - - Object around(): profiled() { - long beforeTime = System.currentTimeMillis(); - try { - return proceed(); - } finally { - long afterTime = System.currentTimeMillis(); - addToProfile(thisJoinPointStaticPart, afterTime - beforeTime); - } - } - - abstract void addToProfile( - org.aspectj.JoinPoint.StaticPart jp, - long elapsed - ); -} -.... - -In order to use either aspect, they must be extended with concrete -aspects, say, MyLogging and MyProfiling. Because advice only applies -from concrete aspects, the declare precedence form only matters when -declaring precedence with concrete aspects. So - -[source, java] -.... -declare precedence: Logging, Profiling; -.... - -has no effect, but both - -[source, java] -.... -declare precedence: MyLogging, MyProfiling; -declare precedence: Logging+, Profiling+; -.... - -are meaningful. - -==== Statically determinable pointcuts - -Pointcuts that appear inside of `declare` forms have certain -restrictions. Like other pointcuts, these pick out join points, but they -do so in a way that is statically determinable. - -Consequently, such pointcuts may not include, directly or indirectly -(through user-defined pointcut declarations) pointcuts that discriminate -based on dynamic (runtime) context. Therefore, such pointcuts may not be -defined in terms of - -* `cflow` -* `cflowbelow` -* `this` -* `target` -* `args` -* `if` - -all of which can discriminate on runtime information. - -[[semantics-aspects]] -=== Aspects - -An aspect is a crosscutting type defined by the `aspect` declaration. - -==== Aspect Declaration - -The `aspect` declaration is similar to the `class` declaration in that -it defines a type and an implementation for that type. It differs in a -number of ways: - -===== Aspect implementation can cut across other types - -In addition to normal Java class declarations such as methods and -fields, aspect declarations can include AspectJ declarations such as -advice, pointcuts, and inter-type declarations. Thus, aspects contain -implementation declarations that can can cut across other types -(including those defined by other aspect declarations). - -===== Aspects are not directly instantiated - -Aspects are not directly instantiated with a new expression, with -cloning, or with serialization. Aspects may have one constructor -definition, but if so it must be of a constructor taking no arguments -and throwing no checked exceptions. - -===== Nested aspects must be `static` - -Aspects may be defined either at the package level, or as a `static` -nested aspect -- that is, a `static` member of a class, interface, or -aspect. If it is not at the package level, the aspect _must_ be defined -with the `static` keyword. Local and anonymous aspects are not allowed. - -==== Aspect Extension - -To support abstraction and composition of crosscutting concerns, aspects -can be extended in much the same way that classes can. Aspect extension -adds some new rules, though. - -===== Aspects may extend classes and implement interfaces - -An aspect, abstract or concrete, may extend a class and may implement a -set of interfaces. Extending a class does not provide the ability to -instantiate the aspect with a new expression: The aspect may still only -define a null constructor. - -===== Classes may not extend aspects - -It is an error for a class to extend or implement an aspect. - -===== Aspects extending aspects - -Aspects may extend other aspects, in which case not only are fields and -methods inherited but so are pointcuts. However, aspects may only extend -abstract aspects. It is an error for a concrete aspect to extend another -concrete aspect. - -==== Aspect instantiation - -Unlike class expressions, aspects are not instantiated with `new` -expressions. Rather, aspect instances are automatically created to cut -across programs. A program can get a reference to an aspect instance -using the static method `aspectOf(..)`. - -Because advice only runs in the context of an aspect instance, aspect -instantiation indirectly controls when advice runs. - -The criteria used to determine how an aspect is instantiated is -inherited from its parent aspect. If the aspect has no parent aspect, -then by default the aspect is a singleton aspect. How an aspect is -instantiated controls the form of the `aspectOf(..)` method defined on -the concrete aspect class. - -===== Singleton Aspects - -* `aspect Id { ... }` -* `aspect Id issingleton() { ... }` - -By default (or by using the modifier `issingleton()`) an aspect has -exactly one instance that cuts across the entire program. That instance -is available at any time during program execution from the static method -`aspectOf()` automatically defined on all concrete aspects -- so, in the -above examples, `A.aspectOf()` will return ``A``'s instance. This aspect -instance is created as the aspect's classfile is loaded. - -Because the an instance of the aspect exists at all join points in the -running of a program (once its class is loaded), its advice will have a -chance to run at all such join points. - -(In actuality, one instance of the aspect `A` is made for each version of -the aspect `A`, so there will be one instantiation for each time `A` is -loaded by a different classloader.) - -===== Per-object aspects - -* `aspect Id perthis( Pointcut ) { ... }` -* `aspect Id pertarget( Pointcut ) { ... }` - -If an aspect `A` is defined `perthis(Pointcut)`, then one object of type `A` -is created for every object that is the executing object (i.e., `this`) -at any of the join points picked out by `Pointcut`. The advice defined -in `A` will run only at a join point where the currently executing object -has been associated with an instance of `A`. - -Similarly, if an aspect `A` is defined `pertarget(Pointcut)`, then one -object of type `A` is created for every object that is the target object -of the join points picked out by `Pointcut`. The advice defined in `A` -will run only at a join point where the target object has been -associated with an instance of `A`. - -In either case, the static method call `A.aspectOf(Object)` can be used -to get the aspect instance (of type `A`) registered with the object. Each -aspect instance is created as early as possible, but not before reaching -a join point picked out by `Pointcut` where there is no associated -aspect of type `A`. - -Both `perthis` and `pertarget` aspects may be affected by code the -AspectJ compiler controls, as discussed in the xref:implementation.adoc#implementation[Implementation Notes] -appendix. - -===== Per-control-flow aspects - -* `aspect Id percflow( Pointcut ) { ... }` -* `aspect Id percflowbelow( Pointcut ) { ... }` - -If an aspect `A` is defined `percflow(Pointcut)` or -`percflowbelow(Pointcut)`, then one object of type `A` is created for each -flow of control of the join points picked out by `Pointcut`, either as -the flow of control is entered, or below the flow of control, -respectively. The advice defined in `A` may run at any join point in or -under that control flow. During each such flow of control, the static -method `A.aspectOf()` will return an object of type `A`. An instance of -the aspect is created upon entry into each such control flow. - -===== Aspect instantiation and advice - -All advice runs in the context of an aspect instance, but it is possible -to write a piece of advice with a pointcut that picks out a join point -that must occur before asopect instantiation. For example: - -[source, java] -.... -public class Client -{ - public static void main(String[] args) { - Client c = new Client(); - } -} - -aspect Watchcall { - pointcut myConstructor(): execution(new(..)); - - before(): myConstructor() { - System.err.println("Entering Constructor"); - } -} -.... - -The before advice should run before the execution of all constructors in -the system. It must run in the context of an instance of the Watchcall -aspect. The only way to get such an instance is to have Watchcall's -default constructor execute. But before that executes, we need to run -the before advice... - -There is no general way to detect these kinds of circularities at -compile time. If advice runs before its aspect is instantiated, AspectJ -will throw a -xref:../api/org/aspectj/lang/NoAspectBoundException.html[`org.aspectj.lang.NoAspectBoundException`]. - -==== Aspect privilege - -* `privileged aspect Id { ... }` - -Code written in aspects is subject to the same access control rules as -Java code when referring to members of classes or aspects. So, for -example, code written in an aspect may not refer to members with default -(package-protected) visibility unless the aspect is defined in the same -package. - -While these restrictions are suitable for many aspects, there may be -some aspects in which advice or inter-type members needs to access -private or protected resources of other types. To allow this, aspects -may be declared `privileged`. Code in priviliged aspects has access to -all members, even private ones. - -[source, java] -.... -class C { - private int i = 0; - void incI(int x) { i = i+x; } -} - -privileged aspect A { - static final int MAX = 1000; - - before(int x, C c): call(void C.incI(int)) && target(c) && args(x) { - if (c.i+x > MAX) throw new RuntimeException(); - } -} -.... - -In this case, if `A` had not been declared `privileged`, the field reference -`c.i` would have resulted in an error signaled by the compiler. - -If a privileged aspect can access multiple versions of a particular -member, then those that it could see if it were not privileged take -precedence. For example, in the code - -[source, java] -.... -class C { - private int i = 0; - void foo() { } -} - -privileged aspect A { - private int C.i = 999; - - before(C c): call(void C.foo()) target(c) { - System.out.println(c.i); - } -} -.... - -``A``'s private inter-type field `C.i`, initially bound to 999, will be -referenced in the body of the advice in preference to ``C``'s privately -declared field, since `A` would have access to its own inter-type -fields even if it were not privileged. - -Note that a privileged aspect can access private inter-type declarations -made by other aspects, since they are simply considered private members -of that other aspect. |