summaryrefslogtreecommitdiffstats
path: root/docs/sandbox/common/language/Initialization.java
blob: 20c308de94aff012cb97c7c53fc8d1ee00b1ab89 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
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();
        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");
            }
        }
        if (0 < errs.length()) {
            throw new Error(errs.toString());
        }
    }    
}
/** @author Erik Hilsdale, Wes Isberg */

// START-SAMPLE language-initialization Understanding object creation join points
/*
 * To work with an object right when it is constructed,
 * 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 {
    String message;
    Thing() {
        this("none");
    }
    Thing(String message) {
        this.message = message;
    }
}

class AnotherThing extends Thing {
    AnotherThing() {
        super(); // this does not append to message as the one below does.
    }
    
    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.
     * 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(..)) { 
        thing.message += " after-any-constructor-call";
    }

    // -------- constructor-execution picks out each body
    /**
     * 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(Thing thing) returning : target(thing) && 
            execution(Thing.new(String)) { 
        thing.message += " after-String-constructor-execution";
    }

    /**
     * DANGER -- BAD!!  Before executing the String constructor,
     * this uses the target object, which is not constructed.
     */
    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 <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.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());
    }
}