diff options
Diffstat (limited to 'docs/progGuideDB/language.adoc')
-rw-r--r-- | docs/progGuideDB/language.adoc | 961 |
1 files changed, 0 insertions, 961 deletions
diff --git a/docs/progGuideDB/language.adoc b/docs/progGuideDB/language.adoc deleted file mode 100644 index 14b662aad..000000000 --- a/docs/progGuideDB/language.adoc +++ /dev/null @@ -1,961 +0,0 @@ -[[language]] -== The AspectJ Language - -[[language-intro]] -=== Introduction - -The previous chapter, xref:gettingstarted.adoc#starting[Getting Started with AspectJ], 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. - -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. - -[[language-anatomy]] -=== The Anatomy of an Aspect - -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. - -==== An Example Aspect - -Here's an example of an aspect definition in AspectJ: - -[source, java] -.... -/*01*/ aspect FaultHandler { -/*02*/ -/*03*/ private boolean Server.disabled = false; -/*04*/ -/*05*/ private void reportFault() { -/*06*/ System.out.println("Failure! Please fix it."); -/*07*/ } -/*08*/ -/*09*/ 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*/ } -.... - -The `FaultHandler` consists of one inter-type field on `Server` (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). - -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. - -==== Pointcuts - -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: - -[source, java] -.... -pointcut services(Server s): target(s) && call(public * *(..)) -.... - -This pointcut, named `services`, picks out those points in the execution -of the program when `Server` objects have their public methods called. -It also allows anyone using the `services` pointcut to access the -`Server` object whose method is being called. - -The idea behind this pointcut in the `FaultHandler` 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. - -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 (`&&`, 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`. - -Pointcuts pick out arbitrarily large numbers of join points of a -program. But they pick out only a small number of _kinds_ 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. - -==== Advice - -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 - -[source, java] -.... -{ - if (s.disabled) throw new DisabledException(); -} -.... - -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. - -The advice in lines 19-22 defines another piece of implementation that -is executed on the same pointcut: - -[source, java] -.... -{ - s.disabled = true; - reportFault(); -} -.... - -But this second method executes after those operations throw exception -of type `FaultException`. - -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. - -[[language-joinPoints]] -=== Join Points and Pointcuts - -Consider the following Java class: - -[source, java] -.... -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; } -} -.... - -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: - -[source, java] -.... -void setX(int x) { this.x = x; } -.... - -This piece of program says that when method named `setX` with an `int` -argument called on an object of type `Point`, then the method body -`{ this.x = x; }` is executed. Similarly, the constructor of the class -states that when an object of type `Point` is instantiated through a -constructor with two `int` arguments, then the constructor body -`{ this.x = x; this.y = y; }` is executed. - -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 consist of things like method calls, method -executions, object instantiations, constructor executions, field -references and handler executions. (See the xref:quickreference.adoc#quick[AspectJ Quick Reference] for a -complete listing.) - -Pointcuts pick out these join points. For example, the pointcut - -[source, java] -.... -pointcut setter(): - target(Point) && - (call(void setX(int)) || call(void setY(int))); -.... - -picks out each call to `setX(int)` or `setY(int)` when called on an -instance of `Point`. Here's another example: - -[source, java] -.... -pointcut ioHandler(): within(MyClass) && handler(IOException); -.... - -This pointcut picks out each the join point when exceptions of type -`IOException` are handled inside the code defined by class `MyClass`. - -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. - -==== Some Example Pointcuts - -Here are examples of pointcuts picking out - -when a particular method body executes:: - `execution(void Point.setX(int))` -when a method is called:: - `call(void Point.setX(int))` -when an exception handler executes:: - `handler(ArrayOutOfBoundsException)` -when the object currently executing (i.e. `this`) is of type -`SomeType`:: - `this(SomeType)` -when the target object is of type `SomeType`:: - `target(SomeType)` -when the executing code belongs to class `MyClass`:: - `within(MyClass)` -when the join point is in the control flow of a call to a ``Test``'s -no-argument `main` method:: - `cflow(call(void Test.main()))` - -Pointcuts compose through the operations `OR` (`||`), `ANT` (`&&`) -and `NOT` (`!`). - -* It is possible to use wildcards. So -[arabic] -. `execution(* *(..))` -. `call(* set(..))` -+ -means (1) the execution of any method regardless of return or parameter -types, and (2) the call to any method named `set` regardless of return -or parameter types -- in case of overloading there may be more than one -such `set` method; this pointcut picks out calls to all of them. -* You can select elements based on types. For example, -[arabic] -. `execution(int *())` -. `call(* setY(long))` -. `call(* Point.setY(int))` -. `call(*.new(int, int))` -+ -means (1) the execution of any method with no parameters that returns an -`int`, (2) the call to any `setY` method that takes a `long` as an -argument, regardless of return type or declaring type, (3) the call to -any of ``Point``'s `setY` methods that take an `int` as an argument, -regardless of return type, and (4) the call to any classes' constructor, -so long as it takes exactly two ``int``s as arguments. -* You can compose pointcuts. For example, -[arabic] -. `target(Point) && call(int *())` -. `call(* *(..)) && (within(Line) || within(Point))` -. `within(*) && execution(*.new(int))` -. `!this(Point) && call(int *(..))` -+ -means (1) any call to an `int` method with no arguments on an instance -of `Point`, regardless of its name, (2) any call to any method where the -call is made from the code in ``Point``'s or ``Line``'s type declaration, -(3) the execution of any constructor taking exactly one `int` argument, -regardless of where the call is made from, and (4) any method call to an -`int` method when the executing object is any type except `Point`. -* You can select methods and constructors based on their modifiers and -on negations of modifiers. For example, you can say: -[arabic] -. `call(public * *(..))` -. `execution(!static * *(..))` -. `execution(public !static * *(..))` -+ -which means (1) any call to a public method, (2) any execution of a -non-static method, and (3) any execution of a public, non-static method. -* Pointcuts can also deal with interfaces. For example, given the -interface -+ -[source, java] -.... -interface MyInterface { ... } -.... -+ -the pointcut `call(* MyInterface.*(..))` picks out any call to a method -in ``MyInterface``'s signature -- that is, any method defined by -`MyInterface` or inherited by one of its a supertypes. - -[[call-vs-execution]] -==== call vs. execution - -When methods and constructors run, there are two interesting times -associated with them. That is when they are called, and when they -actually execute. - -AspectJ exposes these times as call and execution join points, -respectively, and allows them to be picked out specifically by `call` -and `execution` pointcuts. - -So what's the difference between these join points? Well, there are a -number of differences: - -Firstly, the lexical pointcut declarations `within` and `withincode` -match differently. At a call join point, the enclosing code is that of -the call site. This means that `call(void m()) && withincode(void m())` -will only capture directly recursive -calls, for example. At an execution join point, however, the program is -already executing the method, so the enclosing code is the method -itself: `execution(void m()) && withincode(void m())` is the same as -`execution(void m())`. - -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. - -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 `execution`, but if you want to pick one that runs when a particular -_signature_ is called (as is often the case for production aspects), use -`call`. - -==== Pointcut composition - -Pointcuts are put together with the operators and (spelled `&&`), or -(spelled `||`), and not (spelled `!`). 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: - -`cflow(P)` picks out each join point in the control flow of the join -points picked out by `P`. So, pictorially: - -[source, text] -.... -P --------------------- - \ - \ cflow of P - \ -.... - -What does `cflow(P) && cflow(Q)` pick out? Well, it picks out each join point that is -in both the control flow of `P` and in the control flow of `Q`. So... - -[source, text] -.... - P --------------------- - \ - \ cflow of P - \ - \ - \ -Q -------------\------- - \ \ - \ cflow of Q \ cflow(P) && cflow(Q) - \ \ -.... - -Note that `P` and `Q` might not have any join points in common... but -their control flows might have join points in common. - -But what does `cflow(P && Q)` mean? Well, it means the control flow of those join -points that are both picked out by `P` and picked out by `Q`. - -[source, text] -.... -P && Q ------------------- - \ - \ cflow of (P && Q) - \ -.... - -and if there are _no_ join points that are both picked by `P` and picked -out by `Q`, then there's no chance that there are any join points in the -control flow of `(P && Q)`. - -Here's some code that expresses this. - -[source, java] -.... -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"); - } -} -.... - -The `!within(A)` pointcut above is required to avoid the `printPC` -pointcut applying to the `System.out.println` call in the advice body. -If this was not present a recursive call would result as the pointcut -would apply to its own advice. (See xref:pitfalls.adoc#pitfalls-infiniteLoops[Infinite loops] -for more details.) - -==== Pointcut Parameters - -Consider again the first pointcut definition in this chapter: - -[source, java] -.... -pointcut setter(): - target(Point) && - (call(void setX(int)) || call(void setY(int))); -.... - -As we've seen, this pointcut picks out each call to `setX(int)` or -`setY(int)` methods where the target is an instance of `Point`. The -pointcut is given the name `setter` and no parameters on the left-hand -side. An empty parameter list means that none of the context from the -join points is published from this pointcut. But consider another -version of version of this pointcut definition: - -[source, java] -.... -pointcut setter(Point p): - target(p) && - (call(void setX(int)) || call(void setY(int))); -.... - -This version picks out exactly the same join points. But in this -version, the pointcut has one parameter of type `Point`. This means that -any advice that uses this pointcut has access to a `Point` from each -join point picked out by the pointcut. Inside the pointcut definition -this `Point` is named `p` is available, and according to the right-hand -side of the definition, that `Point p` comes from the `target` of each -matched join point. - -Here's another example that illustrates the flexible mechanism for -defining pointcut parameters: - -[source, java] -.... -pointcut testEquality(Point p): - target(Point) && - args(p) && - call(boolean equals(Object)); -.... - -This pointcut also has a parameter of type `Point`. Similar to the -`setter` pointcut, this means that anyone using this pointcut has -access to a `Point` from each join point. But in this case, looking at -the right-hand side we find that the object named in the parameters is -not the target `Point` object that receives the call; it's the argument -(also of type `Point`) passed to the `equals` method when some other -`Point` is the target. If we wanted access to both ``Point``s, then the -pointcut definition that would expose target `Point p1` and argument -`Point p2` would be - -[source, java] -.... -pointcut testEquality(Point p1, Point p2): - target(p1) && - args(p2) && - call(boolean equals(Object)); -.... - -Let's look at another variation of the `setter` pointcut: - -[source, java] -.... -pointcut setter(Point p, int newval): - target(p) && - args(newval) && - (call(void setX(int)) || call(void setY(int))); -.... - -In this case, a `Point` object and an `int` value are exposed by the -named pointcut. Looking at the the right-hand side of the definition, we -find that the `Point` object is the target object, and the `int` value -is the called method's argument. - -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: - -[source, java] -.... -pointcut badPointcut(Point p1, Point p2): - (target(p1) && call(void setX(int))) || - (target(p2) && call(void setY(int))); -.... - -because `p1` is only bound when calling `setX`, and `p2` is only bound -when calling `setY`, but the pointcut picks out all of these join points -and tries to bind both `p1` and `p2`. - -[[example]] -==== Example: `HandleLiveness` - -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 `Partner` objects. The aspect `HandleLiveness` -ensures that, before the delegations, the partner exists and is alive, -or else it throws an exception. - -[source, java] -.... -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 {} -.... - -[[pointcut-best-practice]] -==== Writing good pointcuts - -During compilation, AspectJ processes pointcuts in order to try and -optimize matching performance. Examining code and determining if each -join point matches (statically or dynamically) a given pointcut is a -costly process. (A dynamic match means the match cannot be fully -determined from static analysis and a test will be placed in the code to -determine if there is an actual match when the code is running). On -first encountering a pointcut declaration, AspectJ will rewrite it into -an optimal form for the matching process. What does this mean? Basically -pointcuts are rewritten in DNF (Disjunctive Normal Form) and the -components of the pointcut are sorted such that those components that -are cheaper to evaluate are checked first. This means users do not have -to worry about understanding the performance of various pointcut -designators and may supply them in any order in their pointcut -declarations. - -However, AspectJ can only work with what it is told, and for optimal -performance of matching the user should think about what they are trying -to achieve and narrow the search space for matches as much as they can -in the definition. Basically there are three kinds of pointcut -designator: kinded, scoping and context: - -* Kinded designators are those which select a particular kind of join -point. For example: `execution, get, set, call, handler` -* Scoping designators are those which select a group of join points of -interest (of probably many kinds). For example: `within, withincode` -* Contextual designators are those that match (and optionally bind) -based on context. For example: `this, target, @annotation` - -A well written pointcut should try and include at least the first two -types (kinded and scoping), whilst the contextual designators may be -included if wishing to match based on join point context, or bind that -context for use in the advice. Supplying either just a kinded designator -or just a contextual designator will work but could affect weaving -performance (time and memory used) due to all the extra processing and -analysis. Scoping designators are very fast to match, they can very -quickly dismiss groups of join points that should not be further -processed - that is why a good pointcut should always include one if -possible. - -[[language-advice]] -=== Advice - -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: - -[source, java] -.... -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 - ); -} -.... - -And here is exactly the same example, but using an anonymous pointcut: - -[source, java] -.... -before(Point p1, int newval): - target(p1) && args(newval) - (call(void setX(int)) || call(void setY(int))) -{ - System.out.println( - "About to set something in " + p1 + - " to the new value " + newval - ); -} -.... - -Here are examples of the different advice: - -This before advice runs just before the join points picked out by the -(anonymous) pointcut: - -[source, java] -.... -before(Point p, int x): target(p) && args(x) && call(void setX(int)) { - if (!p.assertX(x)) return; -} -.... - -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: - -[source, java] -.... -after(Point p, int x): - target(p) && args(x) && call(void setX(int)) -{ - if (!p.assertX(x)) throw new PostConditionViolation(); -} -.... - -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 `x` here. After the advice runs, the -return value is returned: - -[source, java] -.... -after(Point p) returning(int x): - target(p) && call(int getX()) -{ - System.out.println("Returning int value " + x + " for p = " + p); -} -.... - -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 -`Exception`. Here the exception value can be accessed with the name `e`. -The advice re-raises the exception after it's done: - -[source, java] -.... -after() throwing(Exception e): - target(Point) && call(void setX(int)) -{ - System.out.println(e); -} -.... - -This around advice traps the execution of the join point; it runs -_instead_ of the join point. The original action associated with the -join point can be invoked through the special `proceed` call: - -[source, java] -.... -void around(Point p, int x): - target(p) - && args(x) - && call(void setX(int)) -{ - if (p.assertX(x)) proceed(p, x); - p.releaseResources(); -} -.... - -[[language-interType]] -=== Inter-type declarations - -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: - -This declares that each `Server` has a `boolean` field named `disabled`, -initialized to `false`: - -[source, java] -.... -private boolean Server.disabled = false; -.... - -It is declared `private`, which means that it is private _to the -aspect_: only code in the aspect can see the field. And even if `Server` -has another private field named `disabled` (declared in `Server` or in -another aspect) there won't be a name collision, since no reference to -`disabled` will be ambiguous. - -This declares that each `Point` has an `int` method named `getX` with no -arguments that returns whatever `this.x` is: - -[source, java] -.... -public int Point.getX() { return this.x; } -.... - -Inside the body, `this` is the `Point` object currently executing. -Because the method is publically declared any code can call it, but if -there is some other `Point.getX()` declared there will be a compile-time -conflict. - -This publically declares a two-argument constructor for `Point`: - -[source, java] -.... -public Point.new(int x, int y) { this.x = x; this.y = y; } -.... - -This publicly declares that each `Point` has an `int` field named `x`, -initialized to zero: - -[source, java] -.... -public int Point.x = 0; -.... - -Because this is publically declared, it is an error if `Point` already -has a field named `x` (defined by `Point` or by another aspect). - -This declares that the `Point` class implements the `Comparable` -interface: - -[source, java] -.... -declare parents: Point implements Comparable; -.... - -Of course, this will be an error unless `Point` defines the methods -required by `Comparable`. - -This declares that the `Point` class extends the `GeometricObject` -class. - -[source, java] -.... -declare parents: Point extends GeometricObject; -.... - -An aspect can have several inter-type declarations. For example, the -following declarations - -[source, java] -.... -public String Point.name; -public void Point.setName(String name) { this.name = name; } -.... - -publicly declare that Point has both a String field `name` and a `void` -method `setName(String)` (which refers to the `name` field declared by -the aspect). - -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: - -[source, java] -.... -aspect A { - private interface HasName {} - declare parents: (Point || Line || Square) implements HasName; - - private String HasName.name; - public String HasName.getName() { return name; } -} -.... - -This declares a marker interface `HasName`, and also declares that any -type that is either `Point`, `Line`, or `Square` implements that -interface. It also privately declares that all `HasName` object have a -`String` field called `name`, and publically declares that all `HasName` -objects have a `String` method `getName()` (which refers to the -privately declared `name` field). - -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. - -==== Inter-type Scope - -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 - -[source, java] -.... -private int Foo.x; -.... - -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, - -[source, java] -.... -int Foo.x; -.... - -then everything in the aspect's package (which may or may not be ``Foo``'s -package) can access `x`. - -==== Example: `PointAssertions` - -The example below consists of one class and one aspect. The aspect -privately declares the assertion methods of `Point`, `assertX` and -`assertY`. It also guards calls to `setX` and `setY` with calls to these -assertion methods. The assertion methods are declared privately because -other parts of the program (including the code in `Point`) have no -business accessing the assert methods. Only the code inside of the -aspect can call those methods. - -[source, java] -.... -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; - } -} -.... - -[[language-thisJoinPoint]] -=== `thisJoinPoint` - -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 -xref:../api/org/aspectj/lang/JoinPoint.html[`org.aspectj.lang.JoinPoint`]. - -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: - -[source, java] -.... -aspect TraceNonStaticMethods { - before(Point p): target(p) && call(* *(..)) { - System.out.println("Entering " + thisJoinPoint + " in " + p); - } -} -.... - -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 such as the arguments of the join point: - -[source, java] -.... -thisJoinPoint.getArgs() -.... - -In addition, it holds an object consisting of all the static information -about the join point such as corresponding line number and static -signature: - -[source, java] -.... -thisJoinPoint.getStaticPart() -.... - -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 `thisJoinPointStaticPart`. Using `thisJoinPointStaticPart` will -avoid the run-time creation of the join point object that may be -necessary when using `thisJoinPoint` directly. - -It is always the case that - -[source, java] -.... -thisJoinPointStaticPart == thisJoinPoint.getStaticPart() - -thisJoinPoint.getKind() == thisJoinPointStaticPart.getKind() -thisJoinPoint.getSignature() == thisJoinPointStaticPart.getSignature() -thisJoinPoint.getSourceLocation() == thisJoinPointStaticPart.getSourceLocation() -.... - -One more reflective variable is available: -`thisEnclosingJoinPointStaticPart`. This, like -`thisJoinPointStaticPart`, 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 - -[source, java] -.... -before() : execution (* *(..)) { - System.err.println(thisEnclosingJoinPointStaticPart.getSourceLocation()) -} -.... |