|
|
@@ -3,21 +3,31 @@ package language; |
|
|
|
|
|
|
|
public class Initialization { |
|
|
|
public static void main(String[] argList) { |
|
|
|
String[] expected = new String[] |
|
|
|
{ "none after-String-constructor-execution after-initialization after-any-constructor-call", |
|
|
|
"hello after-String-constructor-execution after-initialization after-any-constructor-call", |
|
|
|
"none after-String-constructor-execution after-initialization", |
|
|
|
"hi from-AnotherThing after-String-constructor-execution after-initialization" |
|
|
|
}; |
|
|
|
String[] actual = new String[4]; |
|
|
|
Thing thing = new Thing(); |
|
|
|
if (12 != thing.counter) { |
|
|
|
System.err.println("expected 12, got " + thing.counter); |
|
|
|
actual[0] = new Thing().message; |
|
|
|
actual[1] = new Thing("hello").message; |
|
|
|
actual[2] = new AnotherThing().message; |
|
|
|
actual[3] = new AnotherThing("hi").message; |
|
|
|
|
|
|
|
StringBuffer errs = new StringBuffer(); |
|
|
|
for (int i = 0; i < actual.length; i++) { |
|
|
|
if (!expected[i].equals(actual[i])) { |
|
|
|
errs.append("expected "); |
|
|
|
errs.append(expected[i]); |
|
|
|
errs.append(" but got "); |
|
|
|
errs.append(actual[i]); |
|
|
|
errs.append("\n"); |
|
|
|
} |
|
|
|
} |
|
|
|
thing = new Thing(20); |
|
|
|
if (32 != thing.counter) { |
|
|
|
System.err.println("expected 32, got " + thing.counter); |
|
|
|
} |
|
|
|
thing = new AnotherThing(); |
|
|
|
if (2 != thing.counter) { |
|
|
|
System.err.println("expected 2, got " + thing.counter); |
|
|
|
} |
|
|
|
thing = new AnotherThing(20); |
|
|
|
if (23 != thing.counter) { |
|
|
|
System.err.println("expected 23, got " + thing.counter); |
|
|
|
if (0 < errs.length()) { |
|
|
|
throw new Error(errs.toString()); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@@ -29,67 +39,95 @@ public class Initialization { |
|
|
|
* understand the differences between the join points for |
|
|
|
* constructor call, constructor execution, and initialization. |
|
|
|
*/ |
|
|
|
// ------- examples of constructors and the ways they invoke each other. |
|
|
|
class Thing { |
|
|
|
int counter; |
|
|
|
String message; |
|
|
|
Thing() { |
|
|
|
this(1); |
|
|
|
this("none"); |
|
|
|
} |
|
|
|
Thing(int value) { |
|
|
|
counter = value; |
|
|
|
Thing(String message) { |
|
|
|
this.message = message; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
class AnotherThing extends Thing { |
|
|
|
AnotherThing() { |
|
|
|
super(); |
|
|
|
super(); // this does not append to message as the one below does. |
|
|
|
} |
|
|
|
|
|
|
|
AnotherThing(int i) { |
|
|
|
super(++i); |
|
|
|
AnotherThing(String message) { |
|
|
|
super(message + " from-AnotherThing"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
aspect A { |
|
|
|
// -------- constructor-call picks out the calls |
|
|
|
/** |
|
|
|
* After any call to any constructor, fix up the thing. |
|
|
|
* In AspectJ 1.1, this only affects callers in the input |
|
|
|
* classes or source files, but not super calls. |
|
|
|
* When creating an object, there is only one call to |
|
|
|
* construct it, so use call(..) avoid duplicate advice. |
|
|
|
* There is no target for the call, but the object |
|
|
|
* constructed is returned from the call. |
|
|
|
* In AspectJ 1.1, this only picks out callers in the input |
|
|
|
* classes or source files, and it does not pick out |
|
|
|
* invocations via <code>super(..)</code> |
|
|
|
* or <code>this(..)</code>. |
|
|
|
*/ |
|
|
|
after() returning (Thing thing): |
|
|
|
call(Thing.new(..)) { |
|
|
|
postInitialize(thing); |
|
|
|
thing.message += " after-any-constructor-call"; |
|
|
|
} |
|
|
|
|
|
|
|
// -------- constructor-execution picks out each body |
|
|
|
/** |
|
|
|
* After executing the int constructor, fix up the thing. |
|
|
|
* This works regardless of how the constructor was called |
|
|
|
* (by outside code or by super), but only for the |
|
|
|
* specified constructors. |
|
|
|
* After executing the String constructor, fix up the thing. |
|
|
|
* The object being-constructed is available as either |
|
|
|
* <code>this</code> or <code>target</code>. |
|
|
|
* This works even if the constructor was invoked using |
|
|
|
* <code>super()</code> or <code>this()</code> or by code |
|
|
|
* outside the control of the AspectJ compiler. |
|
|
|
* However, if you advise multiple constructors, you'll advise |
|
|
|
* a single instance being constructed multiple times |
|
|
|
* if the constructors call each other. |
|
|
|
* In AspectJ 1.1, this only affects constructors in the input |
|
|
|
* classes or source files. |
|
|
|
*/ |
|
|
|
after() returning (Thing thing): execution(Thing.new(int)) { |
|
|
|
thing.counter++; |
|
|
|
after(Thing thing) returning : target(thing) && |
|
|
|
execution(Thing.new(String)) { |
|
|
|
thing.message += " after-String-constructor-execution"; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* DANGER -- BAD!! Before executing the int constructor, |
|
|
|
* DANGER -- BAD!! Before executing the String constructor, |
|
|
|
* this uses the target object, which is not constructed. |
|
|
|
*/ |
|
|
|
before (Thing thing): this(thing) && execution(Thing.new(int)) { |
|
|
|
// thing.counter++; // DANGER!! thing not constructed yet. |
|
|
|
before (Thing thing): this(thing) && execution(Thing.new(String)) { |
|
|
|
// DANGER!! thing not constructed yet. |
|
|
|
//thing.message += " before-String-constructor-execution"; |
|
|
|
} |
|
|
|
|
|
|
|
// -------- initialization picks out any construction, once |
|
|
|
/** |
|
|
|
* This advises all Thing constructors in one join point, |
|
|
|
* even if they call each other with this(). |
|
|
|
*/ |
|
|
|
* This advises all Thing constructors in one join point, |
|
|
|
* even if they call each other with <code>this()</code>, etc. |
|
|
|
* The object being-constructed is available as either |
|
|
|
* <code>this</code> or <code>target</code>. |
|
|
|
* In AspectJ 1.1, this only affects types input to the compiler. |
|
|
|
*/ |
|
|
|
after(Thing thing) returning: this(thing) |
|
|
|
&& initialization(Thing.new(..)) { |
|
|
|
thing.counter++; |
|
|
|
} |
|
|
|
|
|
|
|
protected void postInitialize(Thing thing) { |
|
|
|
thing.counter += 10; |
|
|
|
thing.message += " after-initialization"; |
|
|
|
} |
|
|
|
} |
|
|
|
//END-SAMPLE language-initialization |
|
|
|
|
|
|
|
aspect B { |
|
|
|
static boolean log = false; |
|
|
|
before() : withincode(void Initialization.main(String[])) |
|
|
|
&& call(Thing.new(..)) && if(log) { |
|
|
|
System.out.println("before: " + thisJoinPointStaticPart.getSourceLocation().getLine()); |
|
|
|
} |
|
|
|
before() : within(A) && adviceexecution() && if(log) { |
|
|
|
System.out.println("advice: " + thisJoinPointStaticPart.getSourceLocation().getLine()); |
|
|
|
} |
|
|
|
} |