aboutsummaryrefslogtreecommitdiffstats
path: root/docs/progGuideDB/semantics.adoc
diff options
context:
space:
mode:
Diffstat (limited to 'docs/progGuideDB/semantics.adoc')
-rw-r--r--docs/progGuideDB/semantics.adoc2618
1 files changed, 2618 insertions, 0 deletions
diff --git a/docs/progGuideDB/semantics.adoc b/docs/progGuideDB/semantics.adoc
new file mode 100644
index 000000000..5a3e7fb00
--- /dev/null
+++ b/docs/progGuideDB/semantics.adoc
@@ -0,0 +1,2618 @@
+[[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.
+
+....
+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`.
+
+....
+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.
+
+....
+abstract aspect A {
+ abstract pointcut publicCall(int i);
+}
+....
+
+In such a case, an extending aspect may override the abstract pointcut.
+
+....
+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:
+
+....
+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
+
+....
+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
+
+....
+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,
+
+....
+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
+
+....
+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
+
+....
+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
+
+....
+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
+
+....
+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.
+
+....
+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
+
+....
+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.
+
+....
+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
+
+....
+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
+
+....
+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
+
+....
+call(public final void C.foo() throws ArrayOutOfBoundsException)
+....
+
+picks out call join points to that method, and the pointcut
+
+....
+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 `ArrayOutOfBounds` exceptions.
+
+The defining type name, if not present, defaults to *, so another way of
+writing that pointcut would be
+
+....
+call(public final void *() throws ArrayOutOfBoundsException)
+....
+
+The wildcard `..` indicates zero or more parameters, so
+
+....
+execution(void m(..))
+....
+
+picks out execution join points for void methods named `m`, of any
+number of arguments, while
+
+....
+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,
+
+....
+withincode(!public void foo())
+....
+
+picks out all join points associated with code in null non-public void
+methods named `foo`, while
+
+....
+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
+
+....
+call(int *())
+....
+
+picks out all call join points to `int` methods regardless of name, but
+
+....
+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
+
+....
+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
+
+....
+class Service implements Runnable {
+ public void run() { ... }
+}
+....
+
+the following pointcut
+
+....
+call(void Service.run())
+....
+
+would fail to pick out the join point for the code
+
+....
+((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:
+
+....
+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
+
+....
+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:
+
+....
+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:
+
+....
+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
+
+<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
+
+____
+void m() throws RuntimeException, IOException \{}
+____
+
+[1] will NOT match the method m(), because method m's throws clause
+declares that it throws IOException. [2] WILL match the method m(),
+because method m's throws clause declares the 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
+
+....
+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
+
+....
+handler(java.util.*Map)
+....
+
+picks out the types java.util.Map and java.util.java.util.HashMap, among
+others, and
+
+....
+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
+
+....
+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
+
+....
+call(Foo.new())
+....
+
+picks out all constructor call join points where an instance of exactly
+type Foo is constructed,
+
+....
+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
+
+....
+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
+
+....
+staticinitialization(Foo || Bar)
+....
+
+picks out the static initializer execution join points of either Foo or
+Bar, and
+
+....
+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:
+
+....
+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
+
+____
+[ 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.
+
+....
+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
+
+....
+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:
+
+....
+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
+
+....
+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:
+
+....
+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:
+
+....
+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.
+
+....
+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
+
+....
+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`:
+
+....
+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.
+
+....
+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`.
+
+....
+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`:
+
+....
+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:
+
+....
+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
+
+....
+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
+
+....
+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:
+
+....
+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
+
+....
+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
+
+....
+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:
+
+....
+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.
+
+....
+ Object M O
+ \ / \ /
+ C N Q
+ \ / /
+ D P
+ \ /
+ E
+....
+
+when a new `E` is instantiated, the initializers run in this order:
+
+....
+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
+
+....
+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
+
+....
+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:
+
+....
+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:
+
+....
+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:
+
+....
+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:
+
+....
+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:
+
+....
+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:
+
+....
+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
+
+....
+declare precedence: Logging, Profiling;
+....
+
+has no effect, but both
+
+....
+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[???]
+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:
+
+....
+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.
+
+....
+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
+
+....
+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 the 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.