- <chapter id="language" xreflabel="The AspectJ Language">
-
- <title>The AspectJ Language</title>
-
- <sect1 id="language-intro">
- <title>Introduction</title>
-
- <para>
- The previous chapter, <xref linkend="starting" />, was a brief
- overview of the AspectJ language. You should read this chapter to
- understand AspectJ's syntax and semantics. It covers the same
- material as the previous chapter, but more completely and in much
- more detail.
- </para>
-
- <para>
- We will start out by looking at an example aspect that we'll build
- out of a pointcut, an introduction, and two pieces of advice. This
- example aspect will gives us something concrete to talk about.
- </para>
- </sect1>
-
- <!-- ============================== -->
-
- <sect1 id="language-anatomy">
- <title>The Anatomy of an Aspect</title>
-
- <para>
- This lesson explains the parts of AspectJ's aspects. By reading this
- lesson you will have an overview of what's in an aspect and you will
- be exposed to the new terminology introduced by AspectJ.
- </para>
-
- <sect2>
- <title>An Example Aspect</title>
-
- <para>
- Here's an example of an aspect definition in AspectJ:
- </para>
-
- <programlisting><![CDATA[
- 1 aspect FaultHandler {
- 2
- 3 private boolean Server.disabled = false;
- 4
- 5 private void reportFault() {
- 6 System.out.println("Failure! Please fix it.");
- 7 }
- 8
- 9 public static void fixServer(Server s) {
- 10 s.disabled = false;
- 11 }
- 12
- 13 pointcut services(Server s): target(s) && call(public * *(..));
- 14
- 15 before(Server s): services(s) {
- 16 if (s.disabled) throw new DisabledException();
- 17 }
- 18
- 19 after(Server s) throwing (FaultException e): services(s) {
- 20 s.disabled = true;
- 21 reportFault();
- 22 }
- 23 }
- ]]></programlisting>
-
- <para>
- The <literal>FaultHandler</literal> consists of one inter-type
- field on <literal>Server</literal> (line 03), two methods (lines
- 05-07 and 09-11), one pointcut definition (line 13), and two pieces
- of advice (lines 15-17 and 19-22).
- </para>
-
- <para>
- This covers the basics of what aspects can contain. In general,
- aspects consist of an association of other program entities,
- ordinary variables and methods, pointcut definitions, inter-type declarations,
- and advice, where advice may be before, after or around advice. The
- remainder of this lesson focuses on those crosscut-related
- constructs.
- </para>
- </sect2>
-
- <sect2>
- <title>Pointcuts</title>
-
- <para>
- AspectJ's pointcut definitions give names to pointcuts. Pointcuts
- themselves pick out join points, i.e. interesting points in the
- execution of a program. These join points can be method or
- constructor invocations and executions, the handling of exceptions,
- field assignments and accesses, etc. Take, for example, the
- pointcut definition in line 13:
- </para>
-
- <programlisting><![CDATA[
- pointcut services(Server s): target(s) && call(public * *(..))
- ]]></programlisting>
-
- <para>
- This pointcut, named <literal>services</literal>, picks out those
- points in the execution of the program when
- <literal>Server</literal> objects have their public methods called.
- It also allows anyone using the <literal>services</literal>
- pointcut to access the <literal>Server</literal> object whose
- method is being called.
- </para>
-
- <para>
- The idea behind this pointcut in the
- <literal>FaultHandler</literal> aspect is that
- fault-handling-related behavior must be triggered on the calls to
- public methods. For example, the server may be unable to proceed
- with the request because of some fault. The calls of those methods
- are, therefore, interesting events for this aspect, in the sense
- that certain fault-related things will happen when these events
- occur.
- </para>
-
- <para>
- Part of the context in which the events occur is exposed by the
- formal parameters of the pointcut. In this case, that consists of
- objects of type <literal>Server</literal>. That formal parameter
- is then being used on the right hand side of the declaration in
- order to identify which events the pointcut refers to. In this
- case, a pointcut picking out join points where a Server is the
- target of some operation (target(s)) is being composed
- (<literal><![CDATA[&&]]></literal>, meaning and) with a pointcut
- picking out call join points (call(...)). The calls are identified
- by signatures that can include wild cards. In this case, there are
- wild cards in the return type position (first *), in the name
- position (second *) and in the argument list position (..); the
- only concrete information is given by the qualifier
- <literal>public</literal>.
- </para>
-
- <para>
- Pointcuts pick out arbitrarily large numbers of join points of a
- program. But they pick out only a small number of
- <emphasis>kinds</emphasis> of join points. Those kinds of join
- points correspond to some of the most important concepts in
- Java. Here is an incomplete list: method call, method execution,
- exception handling, instantiation, constructor execution, and
- field access. Each kind of join point can be picked out by its
- own specialized pointcut that you will learn about in other parts
- of this guide.
- </para>
- </sect2>
-
- <!-- ============================== -->
-
- <sect2>
- <title>Advice</title>
-
- <para>
- A piece of advice brings together a pointcut and a body of code to
- define aspect implementation that runs at join points picked out by
- the pointcut. For example, the advice in lines 15-17 specifies that
- the following piece of code
- </para>
-
- <programlisting><![CDATA[
- {
- if (s.disabled) throw new DisabledException();
- }
- ]]></programlisting>
-
- <para>
- is executed when instances of the <literal>Server</literal> class
- have their public methods called, as specified by the pointcut
- <literal>services</literal>. More specifically, it runs when those
- calls are made, just before the corresponding methods are executed.
- </para>
-
- <para>
- The advice in lines 19-22 defines another piece of implementation
- that is executed on the same pointcut:
- </para>
-
- <programlisting><![CDATA[
- {
- s.disabled = true;
- reportFault();
- }
- ]]></programlisting>
-
- <para>
- But this second method executes after those operations throw
- exception of type <literal>FaultException</literal>.
- </para>
-
- <para>
- There are two other variations of after advice: upon successful
- return and upon return, either successful or with an exception.
- There is also a third kind of advice called around. You will see
- those in other parts of this guide.
- </para>
- </sect2>
-
- </sect1>
-
- <!-- ============================== -->
-
- <sect1 id="language-joinPoints">
- <title>Join Points and Pointcuts</title>
-
- <para>
- Consider the following Java class:
- </para>
-
- <programlisting><![CDATA[
- class Point {
- private int x, y;
-
- Point(int x, int y) { this.x = x; this.y = y; }
-
- void setX(int x) { this.x = x; }
- void setY(int y) { this.y = y; }
-
- int getX() { return x; }
- int getY() { return y; }
- }
- ]]></programlisting>
-
- <para>
- In order to get an intuitive understanding of AspectJ's join points
- and pointcuts, let's go back to some of the basic principles of
- Java. Consider the following a method declaration in class Point:
- </para>
-
- <programlisting><![CDATA[
- void setX(int x) { this.x = x; }
- ]]></programlisting>
-
- <para>
- This piece of program says that that when method named
- <literal>setX</literal> with an <literal>int</literal> argument
- called on an object of type <literal>Point</literal>, then the method
- body <literal>{ this.x = x; }</literal> is executed. Similarly, the
- constructor of the class states that when an object of type
- <literal>Point</literal> is instantiated through a constructor with
- two <literal>int</literal> arguments, then the constructor body
- <literal>{ this.x = x; this.y = y; }</literal> is executed.
- </para>
-
- <para>
- One pattern that emerges from these descriptions is
-
- <blockquote>
- When something happens, then something gets executed.
- </blockquote>
-
- In object-oriented programs, there are several kinds of "things that
- happen" that are determined by the language. We call these the join
- points of Java. Join points consist of things like method calls,
- method executions, object instantiations, constructor executions,
- field references and handler executions. (See the <xref
- linkend="quick" /> for a complete listing.)
- </para>
-
- <para>
- Pointcuts pick out these join points. For example, the pointcut
- </para>
-
- <programlisting><![CDATA[
- pointcut setter(): target(Point) &&
- (call(void setX(int)) ||
- call(void setY(int)));
- ]]></programlisting>
-
- <para>
- picks out each call to <literal>setX(int)</literal> or
- <literal>setY(int)</literal> when called on an instance of
- <literal>Point</literal>. Here's another example:
- </para>
-
- <programlisting><![CDATA[
- pointcut ioHandler(): within(MyClass) && handler(IOException);
- ]]></programlisting>
-
- <para>
- This pointcut picks out each the join point when exceptions of type
- <literal>IOException</literal> are handled inside the code defined by
- class <literal>MyClass</literal>.
- </para>
-
- <para>
- Pointcut definitions consist of a left-hand side and a right-hand side,
- separated by a colon. The left-hand side consists of the pointcut name
- and the pointcut parameters (i.e. the data available when the events
- happen). The right-hand side consists of the pointcut itself.
- </para>
-
- <sect2>
- <title>Some Example Pointcuts</title>
-
- <para>
- Here are examples of pointcuts picking out
- </para>
-
- <variablelist>
- <varlistentry>
- <term>when a particular method body executes</term>
- <listitem>
- <para>
- <literal>execution(void Point.setX(int))</literal>
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>when a method is called</term>
- <listitem>
- <para>
- <literal>call(void Point.setX(int))</literal>
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>when an exception handler executes</term>
- <listitem>
- <para>
- <literal>handler(ArrayOutOfBoundsException)</literal>
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>
- when the object currently executing
- (i.e. <literal>this</literal>) is of type
- <literal>SomeType</literal>
- </term>
- <listitem>
- <para>
- <literal>this(SomeType)</literal>
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>
- when the target object is of type <literal>SomeType</literal>
- </term>
- <listitem>
- <para>
- <literal>target(SomeType)</literal>
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>
- when the executing code belongs to
- class <literal>MyClass</literal>
- </term>
- <listitem>
- <para>
- <literal>within(MyClass)</literal>
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>
- when the join point is in the control flow of a call to a
- <literal>Test</literal>'s no-argument <literal>main</literal>
- method
- </term>
- <listitem>
- <para>
- <literal>cflow(call(void Test.main()))</literal>
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
-
- <para>
- Pointcuts compose through the operations <literal>or</literal>
- ("<literal>||</literal>"), <literal>and</literal>
- ("<literal><![CDATA[&&]]></literal>") and <literal>not</literal>
- ("<literal>!</literal>").
- </para>
-
- <itemizedlist>
- <listitem>
- <para>
- It is possible to use wildcards. So
-
- <orderedlist>
- <listitem>
- <para>
- <literal>execution(* *(..))</literal>
- </para>
- </listitem>
-
- <listitem>
- <para>
- <literal>call(* set(..))</literal>
- </para>
- </listitem>
- </orderedlist>
-
- means (1) the execution of any method regardless of return or
- parameter types, and (2) the call to any method named
- <literal>set</literal> regardless of return or parameter types
- -- in case of overloading there may be more than one such
- <literal>set</literal> method; this pointcut picks out calls to
- all of them.
- </para>
- </listitem>
-
- <listitem>
- <para>
- You can select elements based on types. For example,
- <orderedlist>
- <listitem>
- <para>
- <literal>execution(int *())</literal>
- </para>
- </listitem>
-
- <listitem>
- <para>
- <literal>call(* setY(long))</literal>
- </para>
- </listitem>
-
- <listitem>
- <para>
- <literal>call(* Point.setY(int))</literal>
- </para>
- </listitem>
-
- <listitem>
- <para>
- <literal>call(*.new(int, int))</literal>
- </para>
- </listitem>
-
- </orderedlist>
-
- means (1) the execution of any method with no parameters that
- returns an <literal>int</literal>, (2) the call to any
- <literal>setY</literal> method that takes a
- <literal>long</literal> as an argument, regardless of return
- type or declaring type, (3) the call to any of
- <literal>Point</literal>'s <literal>setY</literal> methods that
- take an <literal>int</literal> as an argument, regardless of
- return type, and (4) the call to any classes' constructor, so
- long as it takes exactly two <literal>int</literal>s as
- arguments.
- </para>
- </listitem>
-
- <listitem>
- <para>
- You can compose pointcuts. For example,
- <orderedlist>
- <listitem>
- <para>
- <literal>target(Point) <![CDATA[&&]]> call(int *())</literal>
- </para>
- </listitem>
-
- <listitem>
- <para>
- <literal>call(* *(..)) <![CDATA[&&]]> (within(Line) || within(Point))</literal>
- </para>
- </listitem>
-
- <listitem>
- <para>
- <literal>within(*) <![CDATA[&&]]> execution(*.new(int))</literal>
- </para>
- </listitem>
-
- <listitem>
- <para>
- <literal>
- !this(Point) <![CDATA[&&]]> call(int *(..))
- </literal>
- </para>
- </listitem>
- </orderedlist>
-
- means (1) any call to an <literal>int</literal> method with no
- arguments on an instance of <literal>Point</literal>,
- regardless of its name, (2) any call to any method where the
- call is made from the code in <literal>Point</literal>'s or
- <literal>Line</literal>'s type declaration, (3) the execution of
- any constructor taking exactly one <literal>int</literal>
- argument, regardless of where the call is made from, and
- (4) any method call to an <literal>int</literal> method when
- the executing object is any type except <literal>Point</literal>.
- </para>
- </listitem>
-
- <listitem>
- <para>
- You can select methods and constructors based on their
- modifiers and on negations of modifiers. For example, you can
- say:
- <orderedlist>
- <listitem>
- <para>
- <literal>call(public * *(..))</literal>
- </para>
- </listitem>
-
- <listitem>
- <para>
- <literal>execution(!static * *(..))</literal>
- </para>
- </listitem>
-
- <listitem>
- <para>
- <literal> execution(public !static * *(..))</literal>
- </para>
- </listitem>
-
- </orderedlist>
- which means (1) any call to a public method, (2) any
- execution of a non-static method, and (3) any execution of a
- public, non-static method.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Pointcuts can also deal with interfaces. For example, given the
- interface </para>
-
- <programlisting><![CDATA[
- interface MyInterface { ... }
- ]]></programlisting>
-
- <para>
- the pointcut <literal>call(* MyInterface.*(..))</literal> picks
- out any call to a method in <literal>MyInterface</literal>'s
- signature -- that is, any method defined by
- <literal>MyInterface</literal> or inherited by one of its a
- supertypes.
- </para>
- </listitem>
-
- </itemizedlist>
- </sect2>
-
- <sect2>
- <title>call vs. execution</title>
-
- <para>
- When methods and constructors run, there are two interesting times
- associated with them. That is when they are called, and when they
- actually execute.
- </para>
-
- <para>
- AspectJ exposes these times as call and execution join points,
- respectively, and allows them to be picked out specifically by
- <literal>call</literal> and <literal>execution</literal> pointcuts.
- </para>
-
- <para>
- So what's the difference between these join points? Well, there are a
- number of differences:
- </para>
-
- <para>
- Firstly, the lexical pointcut declarations
- <literal>within</literal> and <literal>withincode</literal> match
- differently. At a call join point, the enclosing code is that of
- the call site. This means that <literal>call(void m())
- <![CDATA[&&]]> withincode(void m())</literal> will only capture
- directly recursive calls, for example. At an execution join point,
- however, the program is already executing the method, so the
- enclosing code is the method itself: <literal>execution(void m())
- <![CDATA[&&]]> withincode(void m())</literal> is the same as
- <literal>execution(void m())</literal>.
- </para>
-
- <para>
- Secondly, the call join point does not capture super calls to
- non-static methods. This is because such super calls are different in
- Java, since they don't behave via dynamic dispatch like other calls to
- non-static methods.
- </para>
-
- <para>
- The rule of thumb is that if you want to pick a join point that
- runs when an actual piece of code runs (as is often the case for
- tracing), use <literal>execution</literal>, but if you want to pick
- one that runs when a particular <emphasis>signature</emphasis> is
- called (as is often the case for production aspects), use
- <literal>call</literal>.
- </para>
- </sect2>
-
- <!-- ============================== -->
-
- <sect2>
- <title>Pointcut composition</title>
-
- <para>
- Pointcuts are put together with the operators and (spelled
- <literal>&&</literal>), or (spelled <literal>||</literal>),
- and not (spelled <literal>!</literal>). This allows the creation
- of very powerful pointcuts from the simple building blocks of
- primitive pointcuts. This composition can be somewhat confusing
- when used with primitive pointcuts like <literal>cflow</literal>
- and <literal>cflowbelow</literal>. Here's an example:
- </para>
-
- <para>
- <literal>cflow(<replaceable>P</replaceable>)</literal> picks out
- each join point in the control flow of the join points picked out
- by <replaceable>P</replaceable>. So, pictorially:
- </para>
-
- <programlisting>
- P ---------------------
- \
- \ cflow of P
- \
- </programlisting>
-
-
- <para>
- What does <literal>cflow(<replaceable>P</replaceable>) &&
- cflow(<replaceable>Q</replaceable>)</literal> pick out? Well, it
- picks out each join point that is in both the control flow of
- <replaceable>P</replaceable> and in the control flow of
- <replaceable>Q</replaceable>. So...
- </para>
-
- <programlisting>
- P ---------------------
- \
- \ cflow of P
- \
- \
- \
- Q -------------\-------
- \ \
- \ cflow of Q \ cflow(P) && cflow(Q)
- \ \
- </programlisting>
-
- <para>
- Note that <replaceable>P</replaceable> and
- <replaceable>Q</replaceable> might not have any join points in
- common... but their control flows might have join points in common.
- </para>
-
- <para>
- But what does <literal>cflow(<replaceable>P</replaceable>
- && <replaceable>Q</replaceable>)</literal> mean? Well, it
- means the control flow of those join points that are both picked
- out by <replaceable>P</replaceable> and picked out by
- <replaceable>Q</replaceable>.
- </para>
-
- <programlisting>
- P && Q -------------------
- \
- \ cflow of (P && Q)
- \
- </programlisting>
-
- <para>
- and if there are <emphasis>no</emphasis> join points that are both
- picked by <replaceable>P</replaceable> and picked out by
- <replaceable>Q</replaceable>, then there's no chance that there are
- any join points in the control flow of
- <literal>(<replaceable>P</replaceable> &&
- <replaceable>Q</replaceable>)</literal>.
- </para>
-
- <para>
- Here's some code that expresses this.
- </para>
-
- <programlisting><![CDATA[
- public class Test {
- public static void main(String[] args) {
- foo();
- }
- static void foo() {
- goo();
- }
- static void goo() {
- System.out.println("hi");
- }
- }
-
- aspect A {
- pointcut fooPC(): execution(void Test.foo());
- pointcut gooPC(): execution(void Test.goo());
- pointcut printPC(): call(void java.io.PrintStream.println(String));
-
- before(): cflow(fooPC()) && cflow(gooPC()) && printPC() && !within(A) {
- System.out.println("should occur");
- }
-
- before(): cflow(fooPC() && gooPC()) && printPC() && !within(A) {
- System.out.println("should not occur");
- }
- }
- ]]></programlisting>
-
- <para>
- The <literal>!within(<replaceable>A</replaceable>)</literal>
- pointcut above is required to avoid the <literal>printPC</literal>
- pointcut applying to the <literal>System.out.println</literal>
- call in the advice body. If this was not present a recursive call
- would result as the pointcut would apply to it's own advice.
- (See <xref linkend="pitfalls-infiniteLoops"/> for more details.)
- </para>
-
- </sect2>
-
- <!-- ============================== -->
-
- <sect2>
- <title>Pointcut Parameters</title>
-
- <para>
- Consider again the first pointcut definition in this chapter:
- </para>
-
- <programlisting><![CDATA[
- pointcut setter(): target(Point) &&
- (call(void setX(int)) ||
- call(void setY(int)));
- ]]></programlisting>
-
- <para>
- As we've seen, this pointcut picks out each call to
- <literal>setX(int)</literal> or <literal>setY(int)</literal>
- methods where the target is an instance of
- <literal>Point</literal>. The pointcut is given the name
- <literal>setters</literal> and no parameters on the left-hand
- side. An empty parameter list means that none of the context from
- the join points is published from this pointcut. But consider
- another version of version of this pointcut definition:
- </para>
-
- <programlisting><![CDATA[
- pointcut setter(Point p): target(p) &&
- (call(void setX(int)) ||
- call(void setY(int)));
- ]]></programlisting>
-
- <para>
- This version picks out exactly the same join points. But in this
- version, the pointcut has one parameter of type
- <literal>Point</literal>. This means that any advice that uses this
- pointcut has access to a <literal>Point</literal> from each join
- point picked out by the pointcut. Inside the pointcut definition
- this <literal>Point</literal> is named <literal>p</literal> is
- available, and according to the right-hand side of the definition,
- that <literal>Point p</literal> comes from the
- <literal>target</literal> of each matched join point.
- </para>
-
- <para>
- Here's another example that illustrates the flexible mechanism for
- defining pointcut parameters:
- </para>
-
- <programlisting><![CDATA[
- pointcut testEquality(Point p): target(Point) &&
- args(p) &&
- call(boolean equals(Object));
- ]]></programlisting>
-
- <para>
- This pointcut also has a parameter of type
- <literal>Point</literal>. Similar to the
- <literal>setters</literal> pointcut, this means that anyone using
- this pointcut has access to a <literal>Point</literal> from each
- join point. But in this case, looking at the right-hand side we
- find that the object named in the parameters is not the target
- <literal>Point</literal> object that receives the call; it's the
- argument (also of type <literal>Point</literal>) passed to the
- <literal>equals</literal> method when some other
- <literal>Point</literal> is the target. If we wanted access to both
- <literal>Point</literal>s, then the pointcut definition that would
- expose target <literal>Point p1</literal> and argument
- <literal>Point p2</literal> would be
- </para>
-
- <programlisting><![CDATA[
- pointcut testEquality(Point p1, Point p2): target(p1) &&
- args(p2) &&
- call(boolean equals(Object));
- ]]></programlisting>
-
- <para>
- Let's look at another variation of the <literal>setters</literal> pointcut:
- </para>
-
- <programlisting><![CDATA[
- pointcut setter(Point p, int newval): target(p) &&
- args(newval) &&
- (call(void setX(int)) ||
- call(void setY(int)));
- ]]></programlisting>
-
- <para>
- In this case, a <literal>Point</literal> object and an
- <literal>int</literal> value are exposed by the named
- pointcut. Looking at the the right-hand side of the definition, we
- find that the <literal>Point</literal> object is the target object,
- and the <literal>int</literal> value is the called method's
- argument.
- </para>
-
- <para>
- The use of pointcut parameters is relatively flexible. The most
- important rule is that all the pointcut parameters must be bound at
- every join point picked out by the pointcut. So, for example, the
- following pointcut definition will result in a compilation error:
-
- <programlisting><![CDATA[
- pointcut badPointcut(Point p1, Point p2):
- (target(p1) && call(void setX(int))) ||
- (target(p2) && call(void setY(int)));
- ]]></programlisting>
-
- because <literal>p1</literal> is only bound when calling
- <literal>setX</literal>, and <literal>p2</literal> is only bound
- when calling <literal>setY</literal>, but the pointcut picks out
- all of these join points and tries to bind both
- <literal>p1</literal> and <literal>p2</literal>.
- </para>
- </sect2>
-
- <!-- ============================== -->
-
- <sect2>
- <title>Example: <literal>HandleLiveness</literal></title>
-
- <para>
- The example below consists of two object classes (plus an exception
- class) and one aspect. Handle objects delegate their public,
- non-static operations to their <literal>Partner</literal>
- objects. The aspect <literal>HandleLiveness</literal> ensures that,
- before the delegations, the partner exists and is alive, or else it
- throws an exception.
- </para>
-
- <programlisting><![CDATA[
- class Handle {
- Partner partner = new Partner();
-
- public void foo() { partner.foo(); }
- public void bar(int x) { partner.bar(x); }
-
- public static void main(String[] args) {
- Handle h1 = new Handle();
- h1.foo();
- h1.bar(2);
- }
- }
-
- class Partner {
- boolean isAlive() { return true; }
- void foo() { System.out.println("foo"); }
- void bar(int x) { System.out.println("bar " + x); }
- }
-
- aspect HandleLiveness {
- before(Handle handle): target(handle) && call(public * *(..)) {
- if ( handle.partner == null || !handle.partner.isAlive() ) {
- throw new DeadPartnerException();
- }
- }
- }
-
- class DeadPartnerException extends RuntimeException {}
- ]]></programlisting>
-
- </sect2>
- </sect1>
-
- <!-- ============================== -->
-
- <sect1 id="language-advice">
- <title>Advice</title>
-
- <para>
- Advice defines pieces of aspect implementation that execute at
- well-defined points in the execution of the program. Those points can
- be given either by named pointcuts (like the ones you've seen above)
- or by anonymous pointcuts. Here is an example of an advice on a named
- pointcut:
- </para>
-
- <programlisting><![CDATA[
- pointcut setter(Point p1, int newval): target(p1) && args(newval)
- (call(void setX(int) ||
- call(void setY(int)));
-
- before(Point p1, int newval): setter(p1, newval) {
- System.out.println("About to set something in " + p1 +
- " to the new value " + newval);
- }
- ]]></programlisting>
-
- <para>
- And here is exactly the same example, but using an anonymous
- pointcut:
- </para>
-
- <programlisting><![CDATA[
- before(Point p1, int newval): target(p1) && args(newval)
- (call(void setX(int)) ||
- call(void setY(int))) {
- System.out.println("About to set something in " + p1 +
- " to the new value " + newval);
- }
- ]]></programlisting>
-
- <para>
- Here are examples of the different advice:
- </para>
-
- <para>
- This before advice runs just before the join points picked out by the
- (anonymous) pointcut:
- </para>
-
- <programlisting><![CDATA[
- before(Point p, int x): target(p) && args(x) && call(void setX(int)) {
- if (!p.assertX(x)) return;
- }
- ]]></programlisting>
-
- <para>
- This after advice runs just after each join point picked out by the
- (anonymous) pointcut, regardless of whether it returns normally or throws
- an exception:
- </para>
-
- <programlisting><![CDATA[
- after(Point p, int x): target(p) && args(x) && call(void setX(int)) {
- if (!p.assertX(x)) throw new PostConditionViolation();
- }
- ]]></programlisting>
-
- <para>
- This after returning advice runs just after each join point picked
- out by the (anonymous) pointcut, but only if it returns normally.
- The return value can be accessed, and is named <literal>x</literal>
- here. After the advice runs, the return value is returned:
- </para>
-
- <programlisting><![CDATA[
- after(Point p) returning(int x): target(p) && call(int getX()) {
- System.out.println("Returning int value " + x + " for p = " + p);
- }
- ]]></programlisting>
-
- <para>
- This after throwing advice runs just after each join point picked out by
- the (anonymous) pointcut, but only when it throws an exception of type
- <literal>Exception</literal>. Here the exception value can be accessed
- with the name <literal>e</literal>. The advice re-raises the exception
- after it's done:
- </para>
-
- <programlisting><![CDATA[
- after() throwing(Exception e): target(Point) && call(void setX(int)) {
- System.out.println(e);
- }
- ]]></programlisting>
-
- <para>
- This around advice traps the execution of the join point; it runs
- <emphasis>instead</emphasis> of the join point. The original action
- associated with the join point can be invoked through the special
- <literal>proceed</literal> call:
- </para>
-
- <programlisting><![CDATA[
- void around(Point p, int x): target(p)
- && args(x)
- && call(void setX(int)) {
- if (p.assertX(x)) proceed(p, x);
- p.releaseResources();
- }
- ]]></programlisting>
- </sect1>
-
- <!-- ============================== -->
-
- <sect1 id="language-interType">
- <title>Inter-type declarations</title>
-
- <para>
- Aspects can declare members (fields, methods, and constructors) that
- are owned by other types. These are called inter-type members.
- Aspects can also declare that other types implement new interfaces or
- extend a new class. Here are examples of some such inter-type
- declarations:
- </para>
-
- <para>
- This declares that each <literal>Server</literal> has a
- <literal>boolean</literal> field named <literal>disabled</literal>,
- initialized to <literal>false</literal>:
-
- <programlisting><![CDATA[
- private boolean Server.disabled = false;
- ]]></programlisting>
-
- It is declared <literal>private</literal>, which means that it is
- private <emphasis>to the aspect</emphasis>: only code in the aspect
- can see the field. And even if <literal>Server</literal> has
- another private field named <literal>disabled</literal> (declared in
- <literal>Server</literal> or in another aspect) there won't be a name
- collision, since no reference to <literal>disabled</literal> will be
- ambiguous.
- </para>
-
- <para>
- This declares that each <literal>Point</literal> has an
- <literal>int</literal> method named <literal>getX</literal> with no
- arguments that returns whatever <literal>this.x</literal> is:
-
- <programlisting><![CDATA[
- public int Point.getX() { return this.x; }
- ]]></programlisting>
-
- Inside the body, <literal>this</literal> is the
- <literal>Point</literal> object currently executing. Because the
- method is publically declared any code can call it, but if there is
- some other <literal>Point.getX()</literal> declared there will be a
- compile-time conflict.
- </para>
-
- <para>
- This publically declares a two-argument constructor for
- <literal>Point</literal>:
-
- <programlisting><![CDATA[
- public Point.new(int x, int y) { this.x = x; this.y = y; }
- ]]></programlisting>
-
- </para>
-
- <para>
- This publicly declares that each <literal>Point</literal> has an
- <literal>int</literal> field named <literal>x</literal>, initialized
- to zero:
-
- <programlisting><![CDATA[
- public int Point.x = 0;
- ]]></programlisting>
-
- Because this is publically declared, it is an error if
- <literal>Point</literal> already has a field named
- <literal>x</literal> (defined by <literal>Point</literal> or by
- another aspect).
- </para>
-
- <para>
- This declares that the <literal>Point</literal> class implements the
- <literal>Comparable</literal> interface:
-
- <programlisting><![CDATA[
- declare parents: Point implements Comparable;
- ]]></programlisting>
-
- Of course, this will be an error unless <literal>Point</literal>
- defines the methods required by <literal>Comparable</literal>.
- </para>
-
- <para>
- This declares that the <literal>Point</literal> class extends the
- <literal>GeometricObject</literal> class.
-
- <programlisting><![CDATA[
- declare parents: Point extends GeometricObject;
- ]]></programlisting>
- </para>
-
- <para>
- An aspect can have several inter-type declarations. For example, the
- following declarations
-
- <programlisting><![CDATA[
- public String Point.name;
- public void Point.setName(String name) { this.name = name; }
- ]]></programlisting>
-
- publicly declare that Point has both a String field
- <literal>name</literal> and a <literal>void</literal> method
- <literal>setName(String)</literal> (which refers to the
- <literal>name</literal> field declared by the aspect).
- </para>
-
- <para>
- An inter-type member can only have one target type, but often you may
- wish to declare the same member on more than one type. This can be
- done by using an inter-type member in combination with a private
- interface:
-
- <programlisting><![CDATA[
- aspect A {
- private interface HasName {}
- declare parents: (Point || Line || Square) implements HasName;
-
- private String HasName.name;
- public String HasName.getName() { return name; }
- }
- ]]></programlisting>
-
- This declares a marker interface <literal>HasName</literal>, and also declares that any
- type that is either <literal>Point</literal>,
- <literal>Line</literal>, or <literal>Square</literal> implements that
- interface. It also privately declares that all <literal>HasName</literal>
- object have a <literal>String</literal> field called
- <literal>name</literal>, and publically declares that all
- <literal>HasName</literal> objects have a <literal>String</literal>
- method <literal>getName()</literal> (which refers to the privately
- declared <literal>name</literal> field).
- </para>
-
- <para>
- As you can see from the above example, an aspect can declare that
- interfaces have fields and methods, even non-constant fields and
- methods with bodies.
- </para>
-
- <!-- ============================== -->
-
- <sect2>
- <title>Inter-type Scope</title>
-
- <para>
- AspectJ allows private and package-protected (default) inter-type declarations in
- addition to public inter-type declarations. Private means private in
- relation to the aspect, not necessarily the target type. So, if an
- aspect makes a private inter-type declaration of a field
-
- <programlisting><![CDATA[
- private int Foo.x;
- ]]></programlisting>
-
- Then code in the aspect can refer to <literal>Foo</literal>'s
- <literal>x</literal> field, but nobody else can. Similarly, if an
- aspect makes a package-protected introduction,
- </para>
-
- <programlisting><![CDATA[
- int Foo.x;
- ]]></programlisting>
-
- <para>
- then everything in the aspect's package (which may or may not be
- <literal>Foo</literal>'s package) can access <literal>x</literal>.
- </para>
- </sect2>
-
- <!-- ============================== -->
-
- <sect2>
- <title>Example: <literal>PointAssertions</literal></title>
-
- <para>
- The example below consists of one class and one aspect. The aspect
- privately declares the assertion methods of
- <literal>Point</literal>, <literal>assertX</literal> and
- <literal>assertY</literal>. It also guards calls to
- <literal>setX</literal> and <literal>setY</literal> with calls to
- these assertion methods. The assertion methods are declared
- privately because other parts of the program (including the code in
- <literal>Point</literal>) have no business accessing the assert
- methods. Only the code inside of the aspect can call those
- methods.
- </para>
-
- <programlisting><![CDATA[
- class Point {
- int x, y;
-
- public void setX(int x) { this.x = x; }
- public void setY(int y) { this.y = y; }
-
- public static void main(String[] args) {
- Point p = new Point();
- p.setX(3); p.setY(333);
- }
- }
-
- aspect PointAssertions {
-
- private boolean Point.assertX(int x) {
- return (x <= 100 && x >= 0);
- }
- private boolean Point.assertY(int y) {
- return (y <= 100 && y >= 0);
- }
-
- before(Point p, int x): target(p) && args(x) && call(void setX(int)) {
- if (!p.assertX(x)) {
- System.out.println("Illegal value for x"); return;
- }
- }
- before(Point p, int y): target(p) && args(y) && call(void setY(int)) {
- if (!p.assertY(y)) {
- System.out.println("Illegal value for y"); return;
- }
- }
- }
- ]]></programlisting>
-
- </sect2>
- </sect1>
-
- <!-- ================================================== -->
-
- <sect1 id="language-thisJoinPoint">
- <title>thisJoinPoint</title>
-
- <para>
- AspectJ provides a special reference variable,
- <literal>thisJoinPoint</literal>, that contains reflective
- information about the current join point for the advice to use. The
- <literal>thisJoinPoint</literal> variable can only be used in the
- context of advice, just like <literal>this</literal> can only be used
- in the context of non-static methods and variable initializers. In
- advice, <literal>thisJoinPoint</literal> is an object of type <ulink
- url="../api/org/aspectj/lang/JoinPoint.html"><literal>org.aspectj.lang.JoinPoint</literal></ulink>.
- </para>
-
- <para>
- One way to use it is simply to print it out. Like all Java objects,
- <literal>thisJoinPoint</literal> has a <literal>toString()</literal>
- method that makes quick-and-dirty tracing easy:
- </para>
-
- <programlisting><![CDATA[
- class TraceNonStaticMethods {
- before(Point p): target(p) && call(* *(..)) {
- System.out.println("Entering " + thisJoinPoint + " in " + p);
- }
- }
- ]]></programlisting>
-
- <para>
- The type of <literal>thisJoinPoint</literal> includes a rich
- reflective class hierarchy of signatures, and can be used to access
- both static and dynamic information about join points such as the
- arguments of the join point:
-
- <programlisting><![CDATA[
- thisJoinPoint.getArgs()
- ]]></programlisting>
-
- In addition, it holds an object consisting of all the static
- information about the join point such as corresponding line number
- and static signature:
-
- <programlisting><![CDATA[
- thisJoinPoint.getStaticPart()
- ]]></programlisting>
-
- If you only need the static information about the join point, you may
- access the static part of the join point directly with the special
- variable <literal>thisJoinPointStaticPart</literal>. Using
- <literal>thisJoinPointStaticPart</literal> will avoid the run-time
- creation of the join point object that may be necessary when using
- <literal>thisJoinPoint</literal> directly.
- </para>
-
- <para>It is always the case that
- </para>
-
- <programlisting><![CDATA[
- thisJoinPointStaticPart == thisJoinPoint.getStaticPart()
-
- thisJoinPoint.getKind() == thisJoinPointStaticPart.getKind()
- thisJoinPoint.getSignature() == thisJoinPointStaticPart.getSignature()
- thisJoinPoint.getSourceLocation() == thisJoinPointStaticPart.getSourceLocation()
- ]]></programlisting>
-
- <para>
- One more reflective variable is available:
- <literal>thisEnclosingJoinPointStaticPart</literal>. This, like
- <literal>thisJoinPointStaticPart</literal>, only holds the static
- part of a join point, but it is not the current but the enclosing
- join point. So, for example, it is possible to print out the calling
- source location (if available) with
- </para>
-
- <programlisting><![CDATA[
- before() : execution (* *(..)) {
- System.err.println(thisEnclosingJoinPointStaticPart.getSourceLocation())
- }
- ]]></programlisting>
-
- </sect1>
- </chapter>
|