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
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
|
/*******************************************************************************
* Copyright (c) 2008 Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt
*
* Contributors:
* Andy Clement - initial API and implementation
*******************************************************************************/
package org.aspectj.systemtest.ajc169;
import java.lang.reflect.Modifier;
import org.aspectj.apache.bcel.classfile.Field;
import org.aspectj.apache.bcel.classfile.JavaClass;
import org.aspectj.apache.bcel.classfile.Method;
import org.aspectj.apache.bcel.classfile.annotation.AnnotationGen;
import org.aspectj.testing.XMLBasedAjcTestCase;
import junit.framework.Test;
/**
* What would a completely transparent weave be? Is there a minimal subset that makes sense? What is the roadmap to get there? What
* needs testing
*
* --- 'Transparent' here is meaning that the resultant bytecode is more representative of the original declarations, so that it
* looks like the intertype declaration and associated constructs have been seamless added to the affected targets.
*
*
* Fully transparent weaving, what would we like to have: - ITDs appear exactly as declared: 'private int A.i' will create 'private
* int i' in A
*
* - What is the benefit? - although this isn't really in keeping with the AspectJ definition of what an ITD represents, having the
* end result look like the declaration does make it easier for users simply looking at the resultant class file or attempting
* reflection to access what they just ITD'd in place
*
*
* testing For transparent weaving of ITD fields - annotations on new fields - AJDT model - AjType support - what happens to it? -
* advice on within() how does that get affected? - visibility - accessors created when required? - handling clashes with existing
* fields - handling clashes with other aspects - generic declarations - interface declarations - initializers - static and
* non-static - accessibility from advice, for read and write
*
* Design<br>
* The intention will be 'new code' uses the new style whilst old code continues to cause the old code to be built. Whether the code
* wants to use the old or new naming should be apparent from the
*
* @author Andy Clement
*/
public class TransparentWeavingTests extends org.aspectj.testing.XMLBasedAjcTestCase {
// Simple private ITD onto a target
public void testSimplePrivate() throws Exception {
runTest("one - private");
checkForField("OnePrivate", Modifier.PRIVATE, "x");
}
// Default visibility ITD field
public void testSimpleDefault() throws Exception {
runTest("one - default");
checkForField("OneDefault", 0, "x");
}
// annotated private ITD
public void testSimplePrivateAnnotated() throws Exception {
runTest("one - private - annotated");
Field f = checkForField("OnePrivateAnnotated", Modifier.PRIVATE, "x");
AnnotationGen[] annos = f.getAnnotations();
assertTrue(annos.length > 0); // 0==Anno 1==ajcITD
assertEquals("LAnno;", annos[0].getTypeSignature());
}
// annotated default ITD
public void testSimpleDefaultAnnotated() throws Exception {
runTest("one - default - annotated");
Field f = checkForField("OneDefaultAnnotated", 0, "x");
AnnotationGen[] annos = f.getAnnotations();
assertTrue(annos.length > 0); // 0==Anno 1==ajcITD
assertEquals("LAnno;", annos[0].getTypeSignature());
}
// Simple private ITD with getter/setter usage
public void testSimplePrivateWithAccessors() throws Exception {
runTest("one - private - accessors");
}
// check initializer runs OK
public void testSimplePrivateInitializer() throws Exception {
runTest("one - private - initializer");
}
public void testDeclareAtOnPrivateItd() throws Exception {
runTest("declare at on private itd");
Field f = checkForField("OneDeclareAt", Modifier.PRIVATE, "x");
AnnotationGen[] annos = f.getAnnotations();
assertTrue(annos.length > 0); // 1==Anno 0==ajcITD
assertEquals("LAnno;", annos[1].getTypeSignature());
}
// declare @field on a field that already has one
public void testDeclareAtTwo() throws Exception {
runTest("declare at two");
Field f = checkForField("DeclareAtTwo", Modifier.PRIVATE, "x");
AnnotationGen[] annos = f.getAnnotations();
assertTrue(annos.length > 2); // 1==Anno 0==ajcITD
assertEquals("LAnno;", annos[0].getTypeSignature());
assertEquals("LAnno2;", annos[2].getTypeSignature());
}
public void testTwoItdsOnTarget() throws Exception {
runTest("two itds on target");
// Aspect X gets the field, aspect Y gets a mangled one
if (hasField("TwoItdsOnTarget", "ajc$interField$Y$x")) {
checkForField("TwoItdsOnTarget", Modifier.PRIVATE, "x");
checkForField("TwoItdsOnTarget", Modifier.PUBLIC, "ajc$interField$Y$x");
} else {
checkForField("TwoItdsOnTarget", Modifier.PRIVATE, "x");
checkForField("TwoItdsOnTarget", Modifier.PUBLIC, "ajc$interField$X$x");
}
}
public void testTwoItdsOnTargetThatAlreadyHasIt() throws Exception {
runTest("two itds on target that already has it");
// Aspect X gets the field, aspect Y gets a mangled one
checkForField("TwoItdsOnTargetHasAlready", Modifier.PUBLIC, "ajc$interField$X$x");
checkForField("TwoItdsOnTargetHasAlready", Modifier.PUBLIC, "ajc$interField$Y$x");
}
public void testInteractingOldAndNew() throws Exception {
runTest("interacting old and new");
int SYNTHETIC = 0x00001000; // 4096
if (hasField("InteractingOldAndNew", "ajc$interField$Y$i")) {
checkForField("InteractingOldAndNew", Modifier.PRIVATE, "i");
checkForField("InteractingOldAndNew", Modifier.PUBLIC, "ajc$interField$Y$i");
} else {
checkForField("InteractingOldAndNew", Modifier.PRIVATE, "i");
checkForField("InteractingOldAndNew", Modifier.PUBLIC, "ajc$interField$X$i");
}
checkForMethod("InteractingOldAndNew", Modifier.PUBLIC | Modifier.STATIC, "main");
checkForMethod("InteractingOldAndNew", Modifier.PUBLIC | Modifier.STATIC | SYNTHETIC, "ajc$get$i");
checkForMethod("InteractingOldAndNew", Modifier.PUBLIC | Modifier.STATIC | SYNTHETIC, "ajc$set$i");
checkForMethod("InteractingOldAndNew", Modifier.PUBLIC, "getI1");
checkForMethod("InteractingOldAndNew", Modifier.PUBLIC, "getI2");
checkForMethod("InteractingOldAndNew", Modifier.PUBLIC, "setI1");
checkForMethod("InteractingOldAndNew", Modifier.PUBLIC, "setI2");
}
public void testPrivateGenerics() throws Exception {
runTest("generics - private");
Field f = checkForField("Generics", Modifier.PRIVATE, "listOfString");
assertEquals("Ljava/util/List<Ljava/lang/String;>;", f.getGenericSignature());
f = checkForField("Generics", Modifier.PRIVATE, "thing");
assertEquals("TX;", f.getGenericSignature());
}
// ---
private boolean hasField(String clazzname, String name) {
try {
JavaClass jc = getClassFrom(ajc.getSandboxDirectory(), clazzname);
Field[] fs = jc.getFields();
StringBuilder fields = new StringBuilder();
for (Field f : fs) {
fields.append(f.getName()).append(" ");
if (f.getName().equals(name)) {
return true;
}
}
} catch (Exception e) {
return false;
}
return false;
}
private Field checkForField(String clazzname, int modifiers, String name) throws Exception {
JavaClass jc = getClassFrom(ajc.getSandboxDirectory(), clazzname);
Field[] fs = jc.getFields();
StringBuilder fields = new StringBuilder();
for (Field f : fs) {
fields.append(f.getName()).append(" ");
if (f.getName().equals(name)) {
if (f.getModifiers() != modifiers) {
fail("Found field " + name + " in " + clazzname + " but modifiers were wrong, they were " + f.getModifiers());
}
return f;
}
}
fail("Did not find field " + name + " in class " + clazzname + ". Found fields: " + fields.toString());
return null;
}
private Method checkForMethod(String clazzname, int modifiers, String name) throws Exception {
JavaClass jc = getClassFrom(ajc.getSandboxDirectory(), clazzname);
Method[] fs = jc.getMethods();
StringBuilder methods = new StringBuilder();
methods.append("\n");
for (Method f : fs) {
methods.append(f.getName()).append("\n");
if (f.getName().equals(name)) {
if (f.getModifiers() != modifiers) {
fail("Found method " + name + " in " + clazzname + " but modifiers were wrong, they were " + f.getModifiers());
}
return f;
}
System.out.println(f.getGenericSignature());
}
fail("Did not find method " + name + " in class " + clazzname + ". Found methods: " + methods.toString());
return null;
}
// public itd onto a target that already has a field of that name
// just to check what goes wrong and who checks it
public void testPublicClash() throws Exception {
runTest("two");
}
public void testPrivateClash() throws Exception {
runTest("three");
JavaClass jc = getClassFrom(ajc.getSandboxDirectory(), "Three");
Field[] fs = jc.getFields();
for (Field f : fs) {
System.out.println(f);
}
// public int ajc$interField$X$xPrivate [RuntimeVisibleAnnotations]
// public Integer ajc$interField$$yDefault [RuntimeVisibleAnnotations]
// public String zPublic [RuntimeVisibleAnnotations]
}
// --
public static Test suite() {
return XMLBasedAjcTestCase.loadSuite(TransparentWeavingTests.class);
}
@Override
protected java.net.URL getSpecFile() {
return getClassResource("transparentweaving.xml");
}
}
|