]> source.dussan.org Git - aspectj.git/blob
f7ab04d4a291aa32cb00d74f7f650a361e806aa4
[aspectj.git] /
1 /*******************************************************************************
2  * Copyright (c) 2004 IBM All rights reserved. This program and the accompanying
3  * materials are made available under the terms of the Eclipse Public License
4  * v1.0 which accompanies this distribution and is available at
5  * http://www.eclipse.org/legal/epl-v10.html
6  * 
7  * Contributors: Andy Clement - initial implementation
8  ******************************************************************************/
9
10 package org.aspectj.apache.bcel.classfile.tests;
11
12 import java.io.File;
13 import java.util.ArrayList;
14 import java.util.Iterator;
15 import java.util.List;
16
17 import org.aspectj.apache.bcel.Constants;
18 import org.aspectj.apache.bcel.classfile.ConstantPool;
19 import org.aspectj.apache.bcel.classfile.JavaClass;
20 import org.aspectj.apache.bcel.classfile.Method;
21 import org.aspectj.apache.bcel.classfile.annotation.AnnotationElementValue;
22 import org.aspectj.apache.bcel.classfile.annotation.AnnotationGen;
23 import org.aspectj.apache.bcel.classfile.annotation.ArrayElementValue;
24 import org.aspectj.apache.bcel.classfile.annotation.ElementValue;
25 import org.aspectj.apache.bcel.classfile.annotation.NameValuePair;
26 import org.aspectj.apache.bcel.classfile.annotation.SimpleElementValue;
27 import org.aspectj.apache.bcel.generic.ArrayType;
28 import org.aspectj.apache.bcel.generic.ClassGen;
29 import org.aspectj.apache.bcel.generic.InstructionBranch;
30 import org.aspectj.apache.bcel.generic.InstructionConstants;
31 import org.aspectj.apache.bcel.generic.InstructionFactory;
32 import org.aspectj.apache.bcel.generic.InstructionHandle;
33 import org.aspectj.apache.bcel.generic.InstructionList;
34 import org.aspectj.apache.bcel.generic.LocalVariableGen;
35 import org.aspectj.apache.bcel.generic.MethodGen;
36 import org.aspectj.apache.bcel.generic.ObjectType;
37 import org.aspectj.apache.bcel.generic.Type;
38 import org.aspectj.apache.bcel.util.SyntheticRepository;
39
40 /**
41  * The program that some of the tests generate looks like this: public class HelloWorld { public static void main(String[] argv) {
42  * BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); String name = null; try { name = "Andy"; }
43  * catch(IOException e) { return; } System.out.println("Hello, " + name); } }
44  * 
45  */
46 public class GeneratingAnnotatedClassesTest extends BcelTestCase {
47
48         @Override
49         protected void setUp() throws Exception {
50                 super.setUp();
51         }
52
53         /*
54          * Steps in the test: 1) Programmatically construct the HelloWorld program 2) Add two simple annotations at the class level 3)
55          * Save the class to disk 4) Reload the class using the 'static' variant of the BCEL classes 5) Check the attributes are OK
56          */
57         public void testGenerateClassLevelAnnotations() throws ClassNotFoundException {
58
59                 // Create HelloWorld
60                 ClassGen cg = createClassGen("HelloWorld");
61                 ConstantPool cp = cg.getConstantPool();
62                 InstructionList il = new InstructionList();
63
64                 cg.addAnnotation(createSimpleVisibleAnnotation(cp));
65                 cg.addAnnotation(createSimpleInvisibleAnnotation(cp));
66
67                 buildClassContents(cg, cp, il);
68
69                 dumpClass(cg, "HelloWorld.class");
70
71                 JavaClass jc = getClassFrom(".", "HelloWorld");
72
73                 AnnotationGen[] as = jc.getAnnotations();
74                 assertTrue("Should be two annotations but found " + as.length, as.length == 2);
75                 AnnotationGen one = as[0];
76                 AnnotationGen two = as[1];
77                 assertTrue("Name of annotation 1 should be SimpleAnnotation but it is " + as[0].getTypeName(), as[0].getTypeName().equals(
78                                 "SimpleAnnotation"));
79                 assertTrue("Name of annotation 2 should be SimpleAnnotation but it is " + as[1].getTypeName(), as[1].getTypeName().equals(
80                                 "SimpleAnnotation"));
81                 List<NameValuePair> vals = as[0].getValues();
82                 NameValuePair nvp = vals.get(0);
83                 assertTrue("Name of element in SimpleAnnotation should be 'id' but it is " + nvp.getNameString(), nvp.getNameString()
84                                 .equals("id"));
85                 ElementValue ev = nvp.getValue();
86                 assertTrue("Type of element value should be int but it is " + ev.getElementValueType(),
87                                 ev.getElementValueType() == ElementValue.PRIMITIVE_INT);
88                 assertTrue("Value of element should be 4 but it is " + ev.stringifyValue(), ev.stringifyValue().equals("4"));
89                 assertTrue(createTestdataFile("HelloWorld.class").delete());
90         }
91
92         /**
93          * Just check that we can dump a class that has a method annotation on it and it is still there when we read it back in
94          */
95         public void testGenerateMethodLevelAnnotations1() throws ClassNotFoundException {
96                 // Create HelloWorld
97                 ClassGen cg = createClassGen("HelloWorld");
98                 ConstantPool cp = cg.getConstantPool();
99                 InstructionList il = new InstructionList();
100
101                 buildClassContentsWithAnnotatedMethods(cg, cp, il);
102
103                 // Check annotation is OK
104                 int i = cg.getMethods()[0].getAnnotations().length;
105                 assertTrue("Prior to dumping, main method should have 1 annotation but has " + i, i == 1);
106
107                 dumpClass(cg, "temp1" + File.separator + "HelloWorld.class");
108
109                 JavaClass jc2 = getClassFrom("temp1", "HelloWorld");
110
111                 // Check annotation is OK
112                 i = jc2.getMethods()[0].getAnnotations().length;
113                 assertTrue("JavaClass should say 1 annotation on main method but says " + i, i == 1);
114
115                 ClassGen cg2 = new ClassGen(jc2);
116
117                 // Check it now it is a ClassGen
118                 Method[] m = cg2.getMethods();
119                 i = m[0].getAnnotations().length;
120                 assertTrue("The main 'Method' should have one annotation but has " + i, i == 1);
121                 MethodGen mg = new MethodGen(m[0], cg2.getClassName(), cg2.getConstantPool());
122
123                 // Check it finally when the Method is changed to a MethodGen
124                 i = mg.getAnnotations().size();
125                 assertTrue("The main 'MethodGen' should have one annotation but has " + i, i == 1);
126
127                 assertTrue(wipe("temp1" + File.separator + "HelloWorld.class"));
128
129         }
130
131         /**
132          * Going further than the last test - when we reload the method back in, let's change it (adding a new annotation) and then
133          * store that, read it back in and verify both annotations are there !
134          */
135         public void testGenerateMethodLevelAnnotations2() throws ClassNotFoundException {
136                 // Create HelloWorld
137                 ClassGen cg = createClassGen("HelloWorld");
138                 ConstantPool cp = cg.getConstantPool();
139                 InstructionList il = new InstructionList();
140
141                 buildClassContentsWithAnnotatedMethods(cg, cp, il);
142
143                 dumpClass(cg, "temp2", "HelloWorld.class");
144
145                 JavaClass jc2 = getClassFrom("temp2", "HelloWorld");
146
147                 ClassGen cg2 = new ClassGen(jc2);
148
149                 // Main method after reading the class back in
150                 Method mainMethod1 = jc2.getMethods()[0];
151                 assertTrue("The 'Method' should have one annotations but has " + mainMethod1.getAnnotations().length, mainMethod1
152                                 .getAnnotations().length == 1);
153
154                 MethodGen mainMethod2 = new MethodGen(mainMethod1, cg2.getClassName(), cg2.getConstantPool());
155
156                 assertTrue("The 'MethodGen' should have one annotations but has " + mainMethod2.getAnnotations().size(), mainMethod2
157                                 .getAnnotations().size() == 1);
158
159                 mainMethod2.addAnnotation(createFruitAnnotation(cg2.getConstantPool(), "Pear"));
160
161                 cg2.removeMethod(mainMethod1);
162                 cg2.addMethod(mainMethod2.getMethod());
163
164                 dumpClass(cg2, "temp3", "HelloWorld.class");
165
166                 JavaClass jc3 = getClassFrom("temp3", "HelloWorld");
167
168                 ClassGen cg3 = new ClassGen(jc3);
169
170                 Method mainMethod3 = cg3.getMethods()[1];
171                 int i = mainMethod3.getAnnotations().length;
172                 assertTrue("The 'Method' should now have two annotations but has " + i, i == 2);
173
174                 assertTrue(wipe("temp2", "HelloWorld.class"));
175                 assertTrue(wipe("temp3", "HelloWorld.class"));
176         }
177
178         // J5TODO: Need to add deleteFile calls to many of these tests
179
180         /**
181          * Transform simple class from an immutable to a mutable object.
182          */
183         public void testTransformClassToClassGen_SimpleTypes() throws ClassNotFoundException {
184                 JavaClass jc = getClassFrom("testcode.jar", "SimpleAnnotatedClass");
185                 ClassGen cgen = new ClassGen(jc);
186
187                 // Check annotations are correctly preserved
188                 AnnotationGen[] annotations = cgen.getAnnotations();
189                 assertTrue("Expected one annotation but found " + annotations.length, annotations.length == 1);
190         }
191
192         /**
193          * Transform simple class from an immutable to a mutable object. The class is annotated with an annotation that uses an enum.
194          */
195         public void testTransformClassToClassGen_EnumType() throws ClassNotFoundException {
196                 JavaClass jc = getClassFrom("testcode.jar", "AnnotatedWithEnumClass");
197                 ClassGen cgen = new ClassGen(jc);
198
199                 // Check annotations are correctly preserved
200                 AnnotationGen[] annotations = cgen.getAnnotations();
201                 assertTrue("Expected one annotation but found " + annotations.length, annotations.length == 1);
202         }
203
204         /**
205          * Transform simple class from an immutable to a mutable object. The class is annotated with an annotation that uses an array of
206          * SimpleAnnotations.
207          */
208         public void testTransformClassToClassGen_ArrayAndAnnotationTypes() throws ClassNotFoundException {
209                 JavaClass jc = getClassFrom("testcode.jar", "AnnotatedWithCombinedAnnotation");
210                 ClassGen cgen = new ClassGen(jc);
211
212                 // Check annotations are correctly preserved
213                 AnnotationGen[] annotations = cgen.getAnnotations();
214                 assertTrue("Expected one annotation but found " + annotations.length, annotations.length == 1);
215                 AnnotationGen a = annotations[0];
216                 assertTrue("That annotation should only have one value but has " + a.getValues().size(), a.getValues().size() == 1);
217                 NameValuePair nvp = a.getValues().get(0);
218                 ElementValue value = nvp.getValue();
219                 assertTrue("Value should be ArrayElementValueGen but is " + value, value instanceof ArrayElementValue);
220                 ArrayElementValue arrayValue = (ArrayElementValue) value;
221                 assertTrue("Array value should be size one but is " + arrayValue.getElementValuesArraySize(), arrayValue
222                                 .getElementValuesArraySize() == 1);
223                 ElementValue innerValue = arrayValue.getElementValuesArray()[0];
224                 assertTrue("Value in the array should be AnnotationElementValueGen but is " + innerValue,
225                                 innerValue instanceof AnnotationElementValue);
226                 AnnotationElementValue innerAnnotationValue = (AnnotationElementValue) innerValue;
227                 assertTrue("Should be called LSimpleAnnotation; but is called: " + innerAnnotationValue.getAnnotation().getTypeName(),
228                                 innerAnnotationValue.getAnnotation().getTypeSignature().equals("LSimpleAnnotation;"));
229         }
230
231         /**
232          * Transform complex class from an immutable to a mutable object.
233          */
234         public void testTransformComplexClassToClassGen() throws ClassNotFoundException {
235                 JavaClass jc = getClassFrom("testcode.jar", "ComplexAnnotatedClass");
236                 ClassGen cgen = new ClassGen(jc);
237
238                 // Check annotations are correctly preserved
239                 AnnotationGen[] annotations = cgen.getAnnotations();
240                 assertTrue("Expected one annotation but found " + annotations.length, annotations.length == 1);
241                 List<NameValuePair> l = annotations[0].getValues();
242                 boolean found = false;
243                 for (Iterator<NameValuePair> iter = l.iterator(); iter.hasNext();) {
244                         NameValuePair element = iter.next();
245                         if (element.getNameString().equals("dval")) {
246                                 if (((SimpleElementValue) element.getValue()).stringifyValue().equals("33.4"))
247                                         found = true;
248                         }
249                 }
250                 assertTrue("Did not find double annotation value with value 33.4", found);
251         }
252
253         /**
254          * Load a class in and modify it with a new attribute - A SimpleAnnotation annotation
255          */
256         public void testModifyingClasses1() throws ClassNotFoundException {
257                 JavaClass jc = getClassFrom("testcode.jar", "SimpleAnnotatedClass");
258                 ClassGen cgen = new ClassGen(jc);
259                 ConstantPool cp = cgen.getConstantPool();
260                 cgen.addAnnotation(createFruitAnnotation(cp, "Pineapple"));
261                 assertTrue("Should now have two annotations but has " + cgen.getAnnotations().length, cgen.getAnnotations().length == 2);
262                 dumpClass(cgen, "SimpleAnnotatedClass.class");
263                 assertTrue(wipe("SimpleAnnotatedClass.class"));
264         }
265
266         /**
267          * Load a class in and modify it with a new attribute - A ComplexAnnotation annotation
268          */
269         public void testModifyingClasses2() throws ClassNotFoundException {
270                 JavaClass jc = getClassFrom("testcode.jar", "SimpleAnnotatedClass");
271                 ClassGen cgen = new ClassGen(jc);
272                 ConstantPool cp = cgen.getConstantPool();
273                 cgen.addAnnotation(createCombinedAnnotation(cp));
274                 assertTrue("Should now have two annotations but has " + cgen.getAnnotations().length, cgen.getAnnotations().length == 2);
275                 dumpClass(cgen, "SimpleAnnotatedClass.class");
276                 JavaClass jc2 = getClassFrom(".", "SimpleAnnotatedClass");
277                 jc2.getAnnotations();
278                 assertTrue(wipe("SimpleAnnotatedClass.class"));
279                 // System.err.println(jc2.toString());
280         }
281
282         private void dumpClass(ClassGen cg, String fname) {
283                 try {
284                         File f = createTestdataFile(fname);
285                         cg.getJavaClass().dump(f);
286                 } catch (java.io.IOException e) {
287                         System.err.println(e);
288                 }
289         }
290
291         private void dumpClass(ClassGen cg, String dir, String fname) {
292                 dumpClass(cg, dir + File.separator + fname);
293         }
294
295         private void buildClassContentsWithAnnotatedMethods(ClassGen cg, ConstantPool cp, InstructionList il) {
296                 // Create method 'public static void main(String[]argv)'
297                 MethodGen mg = createMethodGen("main", il, cp);
298                 InstructionFactory factory = new InstructionFactory(cg);
299                 mg.addAnnotation(createSimpleVisibleAnnotation(mg.getConstantPool()));
300                 // We now define some often used types:
301
302                 ObjectType i_stream = new ObjectType("java.io.InputStream");
303                 ObjectType p_stream = new ObjectType("java.io.PrintStream");
304
305                 // Create variables in and name : We call the constructors, i.e.,
306                 // execute BufferedReader(InputStreamReader(System.in)) . The reference
307                 // to the BufferedReader object stays on top of the stack and is stored
308                 // in the newly allocated in variable.
309
310                 il.append(factory.createNew("java.io.BufferedReader"));
311                 il.append(InstructionConstants.DUP); // Use predefined constant
312                 il.append(factory.createNew("java.io.InputStreamReader"));
313                 il.append(InstructionConstants.DUP);
314                 il.append(factory.createFieldAccess("java.lang.System", "in", i_stream, Constants.GETSTATIC));
315                 il.append(factory.createInvoke("java.io.InputStreamReader", "<init>", Type.VOID, new Type[] { i_stream },
316                                 Constants.INVOKESPECIAL));
317                 il.append(factory.createInvoke("java.io.BufferedReader", "<init>", Type.VOID,
318                                 new Type[] { new ObjectType("java.io.Reader") }, Constants.INVOKESPECIAL));
319
320                 LocalVariableGen lg = mg.addLocalVariable("in", new ObjectType("java.io.BufferedReader"), null, null);
321                 int in = lg.getIndex();
322                 lg.setStart(il.append(InstructionFactory.createASTORE(in))); // "in" valid from here
323
324                 // Create local variable name and initialize it to null
325
326                 lg = mg.addLocalVariable("name", Type.STRING, null, null);
327                 int name = lg.getIndex();
328                 il.append(InstructionConstants.ACONST_NULL);
329                 lg.setStart(il.append(InstructionFactory.createASTORE(name))); // "name" valid from here
330
331                 // Create try-catch block: We remember the start of the block, read a
332                 // line from the standard input and store it into the variable name .
333
334                 // InstructionHandle try_start = il.append(factory.createFieldAccess(
335                 // "java.lang.System", "out", p_stream, Constants.GETSTATIC));
336
337                 // il.append(new PUSH(cp, "Please enter your name> "));
338                 // il.append(factory.createInvoke("java.io.PrintStream", "print",
339                 // Type.VOID, new Type[] { Type.STRING },
340                 // Constants.INVOKEVIRTUAL));
341                 // il.append(new ALOAD(in));
342                 // il.append(factory.createInvoke("java.io.BufferedReader", "readLine",
343                 // Type.STRING, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
344                 InstructionHandle try_start = il.append(InstructionFactory.PUSH(cp, "Andy"));
345                 il.append(InstructionFactory.createASTORE(name));
346
347                 // Upon normal execution we jump behind exception handler, the target
348                 // address is not known yet.
349
350                 InstructionBranch g = new InstructionBranch(Constants.GOTO);
351                 InstructionHandle try_end = il.append(g);
352
353                 // We add the exception handler which simply returns from the method.
354
355                 LocalVariableGen var_ex = mg.addLocalVariable("ex", Type.getType("Ljava.io.IOException;"), null, null);
356                 int var_ex_slot = var_ex.getIndex();
357
358                 InstructionHandle handler = il.append(InstructionFactory.createASTORE(var_ex_slot));
359                 var_ex.setStart(handler);
360                 var_ex.setEnd(il.append(InstructionConstants.RETURN));
361
362                 mg.addExceptionHandler(try_start, try_end, handler, new ObjectType("java.io.IOException"));
363
364                 // "Normal" code continues, now we can set the branch target of the GOTO
365                 // .
366
367                 InstructionHandle ih = il.append(factory.createFieldAccess("java.lang.System", "out", p_stream, Constants.GETSTATIC));
368                 g.setTarget(ih);
369
370                 // Printing "Hello": String concatenation compiles to StringBuffer
371                 // operations.
372
373                 il.append(factory.createNew(Type.STRINGBUFFER));
374                 il.append(InstructionConstants.DUP);
375                 il.append(InstructionFactory.PUSH(cp, "Hello, "));
376                 il.append(factory.createInvoke("java.lang.StringBuffer", "<init>", Type.VOID, new Type[] { Type.STRING },
377                                 Constants.INVOKESPECIAL));
378                 il.append(InstructionFactory.createALOAD(name));
379                 il.append(factory.createInvoke("java.lang.StringBuffer", "append", Type.STRINGBUFFER, new Type[] { Type.STRING },
380                                 Constants.INVOKEVIRTUAL));
381                 il.append(factory.createInvoke("java.lang.StringBuffer", "toString", Type.STRING, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
382
383                 il.append(factory.createInvoke("java.io.PrintStream", "println", Type.VOID, new Type[] { Type.STRING },
384                                 Constants.INVOKEVIRTUAL));
385                 il.append(InstructionConstants.RETURN);
386
387                 // Finalization: Finally, we have to set the stack size, which normally
388                 // would have to be computed on the fly and add a default constructor
389                 // method to the class, which is empty in this case.
390
391                 mg.setMaxStack();
392                 mg.setMaxLocals();
393                 cg.addMethod(mg.getMethod());
394                 il.dispose(); // Allow instruction handles to be reused
395                 cg.addEmptyConstructor(Constants.ACC_PUBLIC);
396         }
397
398         private void buildClassContents(ClassGen cg, ConstantPool cp, InstructionList il) {
399                 // Create method 'public static void main(String[]argv)'
400                 MethodGen mg = createMethodGen("main", il, cp);
401                 InstructionFactory factory = new InstructionFactory(cg);
402                 // We now define some often used types:
403
404                 ObjectType i_stream = new ObjectType("java.io.InputStream");
405                 ObjectType p_stream = new ObjectType("java.io.PrintStream");
406
407                 // Create variables in and name : We call the constructors, i.e.,
408                 // execute BufferedReader(InputStreamReader(System.in)) . The reference
409                 // to the BufferedReader object stays on top of the stack and is stored
410                 // in the newly allocated in variable.
411
412                 il.append(factory.createNew("java.io.BufferedReader"));
413                 il.append(InstructionConstants.DUP); // Use predefined constant
414                 il.append(factory.createNew("java.io.InputStreamReader"));
415                 il.append(InstructionConstants.DUP);
416                 il.append(factory.createFieldAccess("java.lang.System", "in", i_stream, Constants.GETSTATIC));
417                 il.append(factory.createInvoke("java.io.InputStreamReader", "<init>", Type.VOID, new Type[] { i_stream },
418                                 Constants.INVOKESPECIAL));
419                 il.append(factory.createInvoke("java.io.BufferedReader", "<init>", Type.VOID,
420                                 new Type[] { new ObjectType("java.io.Reader") }, Constants.INVOKESPECIAL));
421
422                 LocalVariableGen lg = mg.addLocalVariable("in", new ObjectType("java.io.BufferedReader"), null, null);
423                 int in = lg.getIndex();
424                 lg.setStart(il.append(InstructionFactory.createASTORE(in))); // "in" valid from here
425
426                 // Create local variable name and initialize it to null
427
428                 lg = mg.addLocalVariable("name", Type.STRING, null, null);
429                 int name = lg.getIndex();
430                 il.append(InstructionConstants.ACONST_NULL);
431                 lg.setStart(il.append(InstructionFactory.createASTORE(name))); // "name" valid from here
432
433                 // Create try-catch block: We remember the start of the block, read a
434                 // line from the standard input and store it into the variable name .
435
436                 // InstructionHandle try_start = il.append(factory.createFieldAccess(
437                 // "java.lang.System", "out", p_stream, Constants.GETSTATIC));
438
439                 // il.append(new PUSH(cp, "Please enter your name> "));
440                 // il.append(factory.createInvoke("java.io.PrintStream", "print",
441                 // Type.VOID, new Type[] { Type.STRING },
442                 // Constants.INVOKEVIRTUAL));
443                 // il.append(new ALOAD(in));
444                 // il.append(factory.createInvoke("java.io.BufferedReader", "readLine",
445                 // Type.STRING, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
446                 InstructionHandle try_start = il.append(InstructionFactory.PUSH(cp, "Andy"));
447                 il.append(InstructionFactory.createASTORE(name));
448
449                 // Upon normal execution we jump behind exception handler, the target
450                 // address is not known yet.
451
452                 InstructionBranch g = new InstructionBranch(Constants.GOTO);
453                 InstructionHandle try_end = il.append(g);
454
455                 // We add the exception handler which simply returns from the method.
456
457                 LocalVariableGen var_ex = mg.addLocalVariable("ex", Type.getType("Ljava.io.IOException;"), null, null);
458                 int var_ex_slot = var_ex.getIndex();
459
460                 InstructionHandle handler = il.append(InstructionFactory.createASTORE(var_ex_slot));
461                 var_ex.setStart(handler);
462                 var_ex.setEnd(il.append(InstructionConstants.RETURN));
463
464                 mg.addExceptionHandler(try_start, try_end, handler, new ObjectType("java.io.IOException"));
465
466                 // "Normal" code continues, now we can set the branch target of the GOTO
467                 // .
468
469                 InstructionHandle ih = il.append(factory.createFieldAccess("java.lang.System", "out", p_stream, Constants.GETSTATIC));
470                 g.setTarget(ih);
471
472                 // Printing "Hello": String concatenation compiles to StringBuffer
473                 // operations.
474
475                 il.append(factory.createNew(Type.STRINGBUFFER));
476                 il.append(InstructionConstants.DUP);
477                 il.append(InstructionFactory.PUSH(cp, "Hello, "));
478                 il.append(factory.createInvoke("java.lang.StringBuffer", "<init>", Type.VOID, new Type[] { Type.STRING },
479                                 Constants.INVOKESPECIAL));
480                 il.append(InstructionFactory.createALOAD(name));
481                 il.append(factory.createInvoke("java.lang.StringBuffer", "append", Type.STRINGBUFFER, new Type[] { Type.STRING },
482                                 Constants.INVOKEVIRTUAL));
483                 il.append(factory.createInvoke("java.lang.StringBuffer", "toString", Type.STRING, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
484
485                 il.append(factory.createInvoke("java.io.PrintStream", "println", Type.VOID, new Type[] { Type.STRING },
486                                 Constants.INVOKEVIRTUAL));
487                 il.append(InstructionConstants.RETURN);
488
489                 // Finalization: Finally, we have to set the stack size, which normally
490                 // would have to be computed on the fly and add a default constructor
491                 // method to the class, which is empty in this case.
492
493                 mg.setMaxStack();
494                 mg.setMaxLocals();
495                 cg.addMethod(mg.getMethod());
496                 il.dispose(); // Allow instruction handles to be reused
497                 cg.addEmptyConstructor(Constants.ACC_PUBLIC);
498         }
499
500         private JavaClass getClassFrom(String where, String clazzname) throws ClassNotFoundException {
501                 SyntheticRepository repos = createRepos(where);
502                 return repos.loadClass(clazzname);
503         }
504
505         // helper methods
506
507         private ClassGen createClassGen(String classname) {
508                 return new ClassGen(classname, "java.lang.Object", "<generated>", Constants.ACC_PUBLIC | Constants.ACC_SUPER, null);
509         }
510
511         private MethodGen createMethodGen(String methodname, InstructionList il, ConstantPool cp) {
512                 return new MethodGen(Constants.ACC_STATIC | Constants.ACC_PUBLIC, // access flags
513                                 Type.VOID, // return type
514                                 new Type[] { new ArrayType(Type.STRING, 1) }, // argument types
515                                 new String[] { "argv" }, // arg names
516                                 methodname, "HelloWorld", // method, class
517                                 il, cp);
518         }
519
520         public AnnotationGen createSimpleVisibleAnnotation(ConstantPool cp) {
521                 SimpleElementValue evg = new SimpleElementValue(ElementValue.PRIMITIVE_INT, cp, 4);
522
523                 NameValuePair nvGen = new NameValuePair("id", evg, cp);
524
525                 ObjectType t = new ObjectType("SimpleAnnotation");
526
527                 List<NameValuePair> elements = new ArrayList<NameValuePair>();
528                 elements.add(nvGen);
529
530                 AnnotationGen a = new AnnotationGen(t, elements, true, cp);
531                 return a;
532         }
533
534         public AnnotationGen createFruitAnnotation(ConstantPool cp, String aFruit) {
535                 SimpleElementValue evg = new SimpleElementValue(ElementValue.STRING, cp, aFruit);
536                 NameValuePair nvGen = new NameValuePair("fruit", evg, cp);
537                 ObjectType t = new ObjectType("SimpleStringAnnotation");
538                 List<NameValuePair> elements = new ArrayList<NameValuePair>();
539                 elements.add(nvGen);
540                 return new AnnotationGen(t, elements, true, cp);
541         }
542
543         public AnnotationGen createCombinedAnnotation(ConstantPool cp) {
544                 // Create an annotation instance
545                 AnnotationGen a = createSimpleVisibleAnnotation(cp);
546                 ArrayElementValue array = new ArrayElementValue(cp);
547                 array.addElement(new AnnotationElementValue(a, cp));
548                 NameValuePair nvp = new NameValuePair("value", array, cp);
549                 List<NameValuePair> elements = new ArrayList<NameValuePair>();
550                 elements.add(nvp);
551                 return new AnnotationGen(new ObjectType("CombinedAnnotation"), elements, true, cp);
552         }
553
554         public AnnotationGen createSimpleInvisibleAnnotation(ConstantPool cp) {
555                 SimpleElementValue evg = new SimpleElementValue(ElementValue.PRIMITIVE_INT, cp, 4);
556
557                 NameValuePair nvGen = new NameValuePair("id", evg, cp);
558
559                 ObjectType t = new ObjectType("SimpleAnnotation");
560
561                 List<NameValuePair> elements = new ArrayList<NameValuePair>();
562                 elements.add(nvGen);
563
564                 AnnotationGen a = new AnnotationGen(t, elements, false, cp);
565                 return a;
566         }
567
568         protected void tearDown() throws Exception {
569                 super.tearDown();
570         }
571
572 }