summaryrefslogtreecommitdiffstats
path: root/tests/java5/generics/genericaspects/GenericAspectX.aj
blob: 837333bb93e057c694f3cb8a49354b812f99fc85 (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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
import java.util.*;
import java.lang.reflect.*;
import org.aspectj.lang.annotation.*;

// This one is 99% the same as the one in the AJDK - the only difference it visibility of some
// components for testing.  Here the type is not public so it can be embedded in this file, and
// the parent/child fields are not private so they can be easily manipulated.

// The aim of the test is to verify the ITDs and the type structure of the programming produced
// during compilation, I am not testing the pointcuts work...

          /** 
           * a generic aspect, we've used descriptive role names for the type variables
           * (Parent and Child) but you could use anything of course
           */
          /*public */ abstract aspect ParentChildRelationship<Parent,Child> {

            /** generic interface implemented by parents */   
            interface ParentHasChildren<C extends ChildHasParent>{
              List<C> getChildren();
              void addChild(C child);
              void removeChild(C child);
            }

            /** generic interface implemented by children */
            interface ChildHasParent<P extends ParentHasChildren>{
              P getParent();
              void setParent(P parent);
            }
          
            /** ensure the parent type implements ParentHasChildren<child type> */
            declare parents: Parent implements ParentHasChildren<Child>;
          
            /** ensure the child type implements ChildHasParent<parent type> */
            declare parents: Child implements ChildHasParent<Parent>;
          
            // Inter-type declarations made on the *generic* interface types to provide 
            // default implementations.
          
            /** list of children maintained by parent */
            public List<C> ParentHasChildren<C>.children = new ArrayList<C>();
          
            /** reference to parent maintained by child */        
            public P ChildHasParent<P>.parent;
          
            /** Default implementation of getChildren for the generic type ParentHasChildren */
            public List<C> ParentHasChildren<C>.getChildren() {
                  return Collections.unmodifiableList(children);  
            }
          
            /** Default implementation of getParent for the generic type ChildHasParent */    
            public P ChildHasParent<P>.getParent() {
                 return parent;
            }
          
            /** 
              * Default implementation of addChild, ensures that parent of child is
              * also updated.
              */ 
            public void ParentHasChildren<C>.addChild(C child) {
                 if (child.parent != null) {
                   child.parent.removeChild(child);
                 }
                 children.add(child);
                 child.parent = this;
              }
          
             /**
               * Default implementation of removeChild, ensures that parent of
               * child is also updated.
               */
             public void ParentHasChildren<C>.removeChild(C child) {
                 if (children.remove(child)) {
                   child.parent = null;
                 }
              }
          
              /**
                * Default implementation of setParent for the generic type ChildHasParent.
                * Ensures that this child is added to the children of the parent too.
                */
              public void ChildHasParent<P>.setParent(P parent) {
                 parent.addChild(this);
              }
          
              /**
                * Matches at an addChild join point for the parent type P and child type C
                */    
              public pointcut addingChild(Parent p, Child c) :
                execution(* Parent.addChild(Child)) && this(p) && args(c);
                
              /**
                * Matches at a removeChild join point for the parent type P and child type C
                */    
              public pointcut removingChild(Parent p, Child c) :
                execution(* Parent.removeChild(Child)) && this(p) && args(c);

          }
          
aspect GenericAspectX extends ParentChildRelationship<Top,Bottom> { 

  public static void main(String []argv) {

    // Check the state of top
    Top t = new Top();
    check(t instanceof ParentHasChildren,"Top should implement ParentHasChildren");
    Type[] intfs = Top.class.getGenericInterfaces();
    check(intfs[0] instanceof ParameterizedType,
          "Expected Top to have parameterized interface but found "+intfs[0]);
    ParameterizedType pt = (ParameterizedType) intfs[0];
    Type[] tArgs = pt.getActualTypeArguments();
    check(tArgs[0]==Bottom.class,
          "Expecting Bottom parameter but found " + tArgs[0]);


    // Check the state of top
    Bottom b = new Bottom();
    check(b instanceof ChildHasParent,"Bottom should implement ChildHasParent");
    intfs = Bottom.class.getGenericInterfaces();
    check(intfs[0] instanceof ParameterizedType,
          "Expected Bottom to have parameterized interface but found "+intfs[0]);
    pt = (ParameterizedType) intfs[0];
    tArgs = pt.getActualTypeArguments();
    check(tArgs[0]==Top.class,
          "Expecting Top parameter but found " + tArgs[0]);




    // Field fiddling
    b.parent = t;
    List<Bottom> kids = new ArrayList<Bottom>();
    kids.add(b);
    t.children = kids;


    // start using the methods
    List<Bottom> kids2 = t.getChildren();
    check(kids2.size()==1,
      "Expected one child of the Top but found "+kids2.size());
    check(kids2.get(0).equals(b),
      "Expected one child of the Top which was what we put in there!"+kids2.get(0));

    // and the parent methods
    Top retrievedParent = b.getParent();
    check(retrievedParent==t,
      "parent check 1 failed "+
      "retrieved="+retrievedParent+"  expected="+t);


    Top top2 = new Top();
    b.setParent(top2);
    Top retrievedParent2 = b.getParent();
    check(retrievedParent2==top2,
      "parent check 2 failed "+
      "retrieved="+retrievedParent2+"  expected="+top2);
    
    Top top3 = new Top();
    Bottom bot2 = new Bottom();
    top3.addChild(bot2);
    Bottom aBottom = top3.getChildren().get(0);
    check(aBottom==bot2,"Incorrect child? expected="+bot2+" found="+aBottom);
    top3.removeChild(bot2);
    int size=top3.getChildren().size();
    check(size==0,"Should be no children but there were "+size);


  }

  public static void check(boolean b,String msg) {
    if (!b) throw new RuntimeException(msg);
  }
}

class Top {}
class Bottom {}