diff options
Diffstat (limited to 'docs/progGuideDB/language.xml')
-rw-r--r-- | docs/progGuideDB/language.xml | 878 |
1 files changed, 477 insertions, 401 deletions
diff --git a/docs/progGuideDB/language.xml b/docs/progGuideDB/language.xml index 6a7a5dda3..709b5c764 100644 --- a/docs/progGuideDB/language.xml +++ b/docs/progGuideDB/language.xml @@ -1,29 +1,34 @@ -<chapter id="aspectjlanguage" xreflabel="The AspectJ Language"> +<chapter id="language" xreflabel="The AspectJ Language"> <title>The AspectJ Language</title> - <sect1> + <sect1 id="language-intro"> <title>Introduction</title> - <para>The previous chapter, <xref linkend="gettingstarted"/>, was a brief + <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. + 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 + <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> - + example aspect will gives us something concrete to talk about. + </para> </sect1> - <sect1 id="AnatomyOfAnAspect"> +<!-- ============================== --> + + <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. + 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> @@ -60,18 +65,19 @@ ]]></programlisting> <para> - The <literal>FaultHandler</literal> consists of one variable introduced - onto <literal>Server</literal> (line 03), two methods (lines 05-07 - and 09-11), one pointcut (line 13), and two pieces of advice (lines - 15-17 and 19-22). + 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 with other program entities, ordinary - variables and methods, pointcuts, introductions, and advice, where - advice may be before, after or around advice. The remainder of this - lesson focuses on those crosscut-related constructs. + 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> @@ -79,11 +85,12 @@ <title>Pointcuts</title> <para> - AspectJ's pointcuts define collections of events, i.e. interesting - points in the execution of a program. These events, or points in the - execution, can be method or constructor invocations and executions, - handling of exceptions, field assignments and accesses, etc. Take, for - example, the pointcut declaration in line 13: + 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[ @@ -91,59 +98,65 @@ 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 instances of the - <literal>Server</literal> class have their public methods called. + 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 + 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 server. 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 public. + 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> - <sect3> - <title>What else?</title> - - <para> - Pointcuts define arbitrarily large sets of points in the execution - of a program. But they use only a finite number of - <emphasis>kinds</emphasis> of points. Those kinds of points - correspond to some of the most important concepts in Java. Here is - an incomplete list: method invocation, method execution, exception - handling, instantiation, constructor execution. Each of these has a - specific syntax that you will learn about in other parts of this - guide. - </para> - </sect3> + <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> - Advice defines pieces of aspect implementation that execute at join - points picked out by a pointcut. For example, the advice in lines 15-17 - specifies that the following piece of code + 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[ @@ -153,10 +166,10 @@ pointcut services(Server s): target(s) && call(public * *(..)) ]]></programlisting> <para> - is executed when instances of the Server class have their public - methods called, as specified by the pointcut services. More - specifically, it runs when those calls are made, just before the - corresponding methods are executed. + 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> @@ -172,24 +185,23 @@ pointcut services(Server s): target(s) && call(public * *(..)) ]]></programlisting> <para> - But this second method executes whenever those operations throw + But this second method executes after those operations throw exception of type <literal>FaultException</literal>. </para> - <sect3> - <title>What else?</title> - <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> - </sect3> + <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> +<!-- ============================== --> + + <sect1 id="language-joinPoints"> <title>Join Points and Pointcuts</title> <para> @@ -211,9 +223,9 @@ class Point { ]]></programlisting> <para> - In order to get an intuitive understanding of AspectJ's pointcuts, let's - go back to some of the basic principles of Java. Consider the following a - method declaration in class Point: + 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[ @@ -221,22 +233,29 @@ void setX(int x) { this.x = x; } ]]></programlisting> <para> - What this piece of program states is that when an object of type Point - has a method called setX with an integer as the argument called on it, - then the method body { this.x = x; } is executed. Similarly, the - constructor given in that class states that when an object of type Point - is instantiated through a constructor with two integers as arguments, - then the constructor body { this.x = x; this.y = y; } is executed. + 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 when something - happens, then something gets executed. 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 comprised - method calls, method executions, instantiations, constructor executions, - field references and handler executions. (See the quick reference for - complete listing.) + 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> @@ -250,9 +269,9 @@ pointcut setter(): target(Point) && ]]></programlisting> <para> - describes the calls to <literal>setX(int)</literal> or - <literal>setY(int)</literal> methods of any instance of Point. Here's - another example: + 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[ @@ -260,31 +279,26 @@ pointcut ioHandler(): within(MyClass) && handler(IOException); ]]></programlisting> <para> - This pointcut picks out the join points at which exceptions of type - IOException are handled inside the code defined by class MyClass. - </para> - - <para> - Pointcuts consist of a left-hand side and a right-hand side, separated by - a colon. The left-hand side defines the pointcut name and the pointcut - parameters (i.e. the data available when the events happen). The - right-hand side defines the events in the pointcut. + 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> - Pointcuts can then be used to define aspect code in advice, as we will - see later. But first let's see what types of events can be captured and - how they are described in AspectJ. + 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>Designators</title> + <title>Some Example Pointcuts</title> <para> - Here are examples of designators of + Here are examples of pointcuts picking out </para> - <variablelist> + <variablelist> <varlistentry> <term>when a particular method body executes</term> <listitem> @@ -313,8 +327,11 @@ pointcut ioHandler(): within(MyClass) && handler(IOException); </varlistentry> <varlistentry> - <term>when the object currently executing - (i.e. <literal>this</literal>) is of type <literal>SomeType</literal></term> + <term> + when the object currently executing + (i.e. <literal>this</literal>) is of type + <literal>SomeType</literal> + </term> <listitem> <para> <literal>this(SomeType)</literal> @@ -323,8 +340,9 @@ pointcut ioHandler(): within(MyClass) && handler(IOException); </varlistentry> <varlistentry> - <term>when the target object is of type - <literal>SomeType</literal></term> + <term> + when the target object is of type <literal>SomeType</literal> + </term> <listitem> <para> <literal>target(SomeType)</literal> @@ -333,8 +351,10 @@ pointcut ioHandler(): within(MyClass) && handler(IOException); </varlistentry> <varlistentry> - <term>when the executing code belongs to - class <literal>MyClass</literal></term> + <term> + when the executing code belongs to + class <literal>MyClass</literal> + </term> <listitem> <para> <literal>within(MyClass)</literal> @@ -343,9 +363,11 @@ pointcut ioHandler(): within(MyClass) && handler(IOException); </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> + <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(void Test.main())</literal> @@ -355,7 +377,7 @@ pointcut ioHandler(): within(MyClass) && handler(IOException); </variablelist> <para> - Designators compose through the operations <literal>or</literal> + Pointcuts compose through the operations <literal>or</literal> ("<literal>||</literal>"), <literal>and</literal> ("<literal><![CDATA[&&]]></literal>") and <literal>not</literal> ("<literal>!</literal>"). @@ -365,6 +387,7 @@ pointcut ioHandler(): within(MyClass) && handler(IOException); <listitem> <para> It is possible to use wildcards. So + <orderedlist> <listitem> <para> @@ -378,10 +401,13 @@ pointcut ioHandler(): within(MyClass) && handler(IOException); </para> </listitem> </orderedlist> - means (1) all the executions of methods with any return and - parameter types and (2) method calls of set methods with any - return and parameter types -- in case of overloading there may be - more than one; this designator picks out all of them. + + 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> @@ -414,21 +440,23 @@ pointcut ioHandler(): within(MyClass) && handler(IOException); </listitem> </orderedlist> - means (1) all executions of methods with no parameters, returning - an <literal>int</literal> (2) the calls of - <literal>setY</literal> methods that take a - <literal>long</literal> as an argument, regardless of their return - type or defining type, (3) the calls of class + + 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 the - return type, and (4) the calls of all classes' constructors that - take two <literal>int</literal>s as arguments. + 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 designators. For example, + You can compose pointcuts. For example, <orderedlist> <listitem> <para> @@ -450,30 +478,30 @@ pointcut ioHandler(): within(MyClass) && handler(IOException); <listitem> <para> - <literal>this(*) <![CDATA[&&]]> !this(Point) <![CDATA[&&]]> - call(int *(..))</literal> + <literal> + !this(Point) <![CDATA[&&]]> call(int *(..)) + </literal> </para> </listitem> </orderedlist> - means (1) all calls to methods received by instances of class - <literal>Point</literal>, with no parameters, returning an - <literal>int</literal>, (2) calls to any method where the call is - made from the code in <literal>Point</literal>'s or - <literal>Line</literal>'s type declaration, (3) executions of - constructors of all classes, that take an <literal>int</literal> as - an argument, and - (4) all method calls of any method returning an - <literal>int</literal>, from all objects except - <literal>Point</literal> objects to any other objects. - + 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: + You can select methods and constructors based on their + modifiers and on negations of modifiers. For example, you can + say: <orderedlist> <listitem> <para> @@ -494,23 +522,27 @@ pointcut ioHandler(): within(MyClass) && handler(IOException); </listitem> </orderedlist> - which means (1) all invocation of public methods, (2) all - executions of non-static methods, and (3) all signatures of - the public, non-static methods. + 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> - Designators can also deal with interfaces. For example, given the + Pointcuts can also deal with interfaces. For example, given the interface </para> - <programlisting><![CDATA[ -interface MyInterface { ... }]]></programlisting> +<programlisting><![CDATA[ +interface MyInterface { ... } +]]></programlisting> - <para> the designator <literal>call(* MyInterface.*(..))</literal> - picks out the call join points for methods defined by the interface - <literal>MyInterface</literal> (or its superinterfaces). + <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> @@ -528,55 +560,64 @@ interface MyInterface { ... }]]></programlisting> <para> AspectJ exposes these times as call and execution join points, - respectively, and allows them to be picked out specifically by call and - execution pointcuts. + 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 times? Well, there are a number - of differences: + 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 text is that of the call site. This means that - This means that <literal>call(void m()) <![CDATA[&&]]> within(void m())</literal> - will only capture recursive calls, for example. At an execution join - point, however, the control is already executing the method. + 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. + 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, pick an execution, but if you want - to pick one that runs when a particular signature is called, pick a - call. + 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 cflow and cflowbelow. Here's an example: + <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 - the join points in the control flow of the join points picked out by - <replaceable>P</replaceable>. So, pictorially: + <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> @@ -587,11 +628,12 @@ interface MyInterface { ... }]]></programlisting> </programlisting> - <para>What does <literal>cflow(<replaceable>P</replaceable>) && - cflow(<replaceable>Q</replaceable>)</literal> pick out? Well, it picks - out those join points that are in both the control flow of - <replaceable>P</replaceable> and in the control flow of - <replaceable>Q</replaceable>. So... + <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> @@ -607,15 +649,18 @@ interface MyInterface { ... }]]></programlisting> \ \ </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> + 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> picked out by <replaceable>Q</replaceable>. + <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> @@ -625,21 +670,24 @@ interface MyInterface { ... }]]></programlisting> \ </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> + 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> + Here's some code that expresses this. </para> <programlisting><![CDATA[ public class Test { public static void main(String[] args) { foo(); - } + } static void foo() { goo(); } @@ -649,7 +697,6 @@ public class Test { } aspect A { - pointcut fooPC(): execution(void Test.foo()); pointcut gooPC(): execution(void Test.goo()); pointcut printPC(): call(void java.io.PrintStream.println(String)); @@ -661,17 +708,18 @@ aspect A { before(): cflow(fooPC() && gooPC()) && printPC() { System.out.println("should not occur"); } - } ]]></programlisting> </sect2> +<!-- ============================== --> + <sect2> <title>Pointcut Parameters</title> <para> - Consider, for example, the first pointcut you've seen here, + Consider again the first pointcut definition in this chapter: </para> <programlisting><![CDATA[ @@ -681,13 +729,14 @@ aspect A { ]]></programlisting> <para> - As we've seen before, the right-hand side of the pointcut picks out the - calls to <literal>setX(int)</literal> or <literal>setY(int)</literal> - methods where the target is any object of type - <literal>Point</literal>. On the left-hand side, the pointcut is given - the name "setters" and no parameters. An empty parameter list means - that when those events happen no context is immediately available. But - consider this other version of the same pointcut: + 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[ @@ -697,13 +746,15 @@ aspect A { ]]></programlisting> <para> - This version picks out exactly the same calls. But in this version, the - pointcut has one parameter of type <literal>Point</literal>. This means - that when the events described on the right-hand side happen, a - <literal>Point</literal> object, named by a parameter named "p", is - available. According to the right-hand side of the pointcut, that - <literal>Point</literal> object in the pointcut parameters is the - object that receives the calls. + 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> @@ -718,16 +769,19 @@ aspect A { ]]></programlisting> <para> - This pointcut also has a parameter of type <literal>Point</literal>. - Similarly to the "setters" pointcut, this means that when the events - described on the right-hand side happen, a <literal>Point</literal> - object, named by a parameter named "p", is available. 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 (of type Point) passed to the "equals" method on some other - target Point object. If we wanted access to both objects, then the pointcut - definition that would define target <literal>Point p1</literal> - and argument <literal>Point p2</literal> would be + 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[ @@ -737,7 +791,7 @@ aspect A { ]]></programlisting> <para> - Let's look at another variation of the "setters" pointcut: + Let's look at another variation of the <literal>setters</literal> pointcut: </para> <programlisting><![CDATA[ @@ -748,49 +802,47 @@ pointcut setter(Point p, int newval): target(p) && ]]></programlisting> <para> - In this case, a <literal>Point</literal> object and an integer value - are available when the calls happen. Looking at the events definition - on the right-hand side, we find that the <literal>Point</literal> - object is the object receiving the call, and the integer - value is the argument of the method . + 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 definition of pointcut parameters is relatively flexible. The most - important rule is that when each of those events defined in the - right-hand side happen, all the pointcut parameters must be bound to - some value. So, for example, the following pointcut definition will - result in a compilation error: - </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 xcut(Point p1, Point p2): + pointcut badPointcut(Point p1, Point p2): (target(p1) && call(void setX(int))) || (target(p2) && call(void setY(int))); ]]></programlisting> - <para> - The right-hand side establishes that this pointcut picks out the call - join points consisting of the <literal>setX(int)</literal> method - called on a point object, or the <literal>setY(int)</literal> method - called on a point object. This is fine. The problem is that the - parameters definition tries to get access to two point objects. But - when <literal>setX(int)</literal> is called on a point object, there is - no other point object to grab! So in that case, the parameter - <literal>p2</literal> is unbound, and hence, the compilation error. + 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> + 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 { @@ -824,17 +876,19 @@ pointcut setter(Point p, int newval): target(p) && ]]></programlisting> </sect2> - </sect1> - <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: + 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[ @@ -866,6 +920,11 @@ pointcut setter(Point p, int newval): target(p) && 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; @@ -873,8 +932,9 @@ pointcut setter(Point p, int newval): target(p) && ]]></programlisting> <para> - This before advice runs just before the execution of the actions - associated with the events in the (anonymous) pointcut. + 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[ @@ -884,9 +944,10 @@ pointcut setter(Point p, int newval): target(p) && ]]></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. + 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[ @@ -896,10 +957,11 @@ pointcut setter(Point p, int newval): target(p) && ]]></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. + 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[ @@ -909,11 +971,10 @@ pointcut setter(Point p, int newval): target(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. + 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[ @@ -924,146 +985,167 @@ void around(Point p, int x): target(p) p.releaseResources(); } ]]></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> - </sect1> - <sect1> - <title>Introduction</title> +<!-- ============================== --> + + <sect1 id="language-interType"> + <title>Inter-type declarations</title> <para> - Introduction declarations add whole new elements in the given types, and - so change the type hierarchy. Here are examples of introduction + 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> - <para> - This privately introduces a field named <literal>disabled</literal> in - <literal>Server</literal> and initializes it to - <literal>false</literal>. Because it is declared - <literal>private</literal>, only code defined in the aspect can access - the field. + 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 x; } + public int Point.getX() { return this.x; } ]]></programlisting> - <para> - This publicly introduces a method named <literal>getX</literal> in - <literal>Point</literal>; the method returns an <literal>int</literal>, - it has no arguments, and its body is return <literal>x</literal>. - Because it is defined publically, any code can call it. + 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> - This publicly introduces a constructor in Point; the constructor has - two arguments of type int, and its body is this.x = x; this.y = y; </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> - <para> - This publicly introduces a field named x of type int in Point; the - field is initialized to 0. + 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> - <para> - This declares that the <literal>Point</literal> class now implements the - <literal>Comparable</literal> interface. Of course, this will be an error - unless <literal>Point</literal> defines the methods of - <literal>Comparable</literal>. + 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> - This declares that the <literal>Point</literal> class now extends the - <literal>GeometricObject</literal> class. </para> <para> - An aspect can introduce several elements in at the same time. For - example, the following declaration - </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> - <para> - publicly introduces both a field and a method into class - <literal>Point</literal>. Note that the identifier "name" in the body of - the method is bound to the "name" field in <literal>Point</literal>, even - if the aspect defined another field called "name". + 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> - One declaration can introduce several elements in several classes as - well. For example, - </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[ - public String (Point || Line || Square).getName() { return name; } + aspect A { + private interface HasName {} + declare parents: (Point || Line || Square) implements HasName; + + private String HasName.name; + public String HasName.getName() { return name; } + } ]]></programlisting> - <para> - publicly introduces three methods, one in <literal>Point</literal>, - another in Line and another in <literal>Square</literal>. The three - methods have the same name (getName), no parameters, return a String, and - have the same body (return name;). The purpose of introducing several - elements in one single declaration is that their bodies are the same. The - introduction is an error if any of <literal>Point</literal>, - <literal>Line</literal>, or <literal>Square</literal> do not have a - "name" field. + 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> - An aspect can introduce fields and methods (even with bodies) onto - interfaces as well as classes. + 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>Introduction Scope</title> + <title>Inter-type Scope</title> <para> - AspectJ allows private and package-protected (default) introduction in - addition to public introduction. Private introduction means private in + 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 introduction of a field on a type - </para> + aspect makes a private inter-type declaration of a field <programlisting><![CDATA[ private int Foo.x; ]]></programlisting> - <para> - Then code in the aspect can refer to Foo's x field, but nobody else - can. Similarly, if an aspect makes a package-protected - introduction, + 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[ @@ -1071,22 +1153,27 @@ void around(Point p, int x): target(p) ]]></programlisting> <para> - then everything in the aspect's package (which may not be Foo's - package) can access x. + 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 - introduces all implementation that is related with assertions of the - class. It privately introduces two methods in the class Point, namely - assertX and assertY. It also advises the two set methods of Point with - before declarations that assert the validity of the given values. The - introductions are made privately because other parts of the program - have no business accessing the assert methods. Only the code inside of - the aspect can call those methods. + 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[ @@ -1124,27 +1211,29 @@ void around(Point p, int x): target(p) } ]]></programlisting> - </sect2> + </sect2> </sect1> <!-- ================================================== --> - <sect1> - <title>Reflection</title> + <sect1 id="language-thisJoinPoint"> + <title>thisJoinPoint</title> <para> - AspectJ provides a special reference variable, thisJoinPoint, that - contains reflective information about the current join point for the - advice to use. The thisJoinPoint variable can only be used in the context - of advice, just like this can only be used in the context of non-static - methods and variable initializers. In advice, thisJoinPoint is an object - of type JoinPoint. + 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, - thisJoinPoint has a toString() method that makes quick-and-dirty tracing - easy. + 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[ @@ -1156,33 +1245,29 @@ void around(Point p, int x): target(p) ]]></programlisting> <para> - The type of thisJoinPoint includes a rich reflective class hierarchy of - signatures, and can be used to access both static and dynamic information - about join points. If, however, only the static information about the - join point (such as the Signature) is desired, a lightweight join-point - object is available from the thisJoinPointStaticPart special variable. - This object is the same object you would get from - </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.getStaticPart() + thisJoinPoint.getArgs() ]]></programlisting> - <para> - The static part of a join point does not include dynamic information, - such as the arguments, which can be accessed with - </para> + 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.getArgs() + thisJoinPoint.getStaticPart() ]]></programlisting> - <para> - But it has the performance benefit that repeated execution of the code - containing <literal>thisJoinPointStaticPart</literal> (through, for - example, separate method calls) will not result in repeated construction - of the reflective object. + 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 @@ -1199,13 +1284,12 @@ void around(Point p, int x): target(p) <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 + <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()) @@ -1213,12 +1297,4 @@ void around(Point p, int x): target(p) ]]></programlisting> </sect1> - </chapter> - -<!-- Local variables: --> -<!-- fill-column: 79 --> -<!-- compile-command: "ant -quiet prog-html" --> -<!-- sgml-local-ecat-files: progguide.ced --> -<!-- sgml-parent-document:("progguide.xml" "book" "chapter") --> -<!-- End: --> |