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
7 * Contributors: Andy Clement - initial implementation
8 ******************************************************************************/
10 package org.aspectj.apache.bcel.classfile.tests;
13 import java.util.ArrayList;
14 import java.util.Iterator;
15 import java.util.List;
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;
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); } }
46 public class GeneratingAnnotatedClassesTest extends BcelTestCase {
49 protected void setUp() throws Exception {
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
57 public void testGenerateClassLevelAnnotations() throws ClassNotFoundException {
60 ClassGen cg = createClassGen("HelloWorld");
61 ConstantPool cp = cg.getConstantPool();
62 InstructionList il = new InstructionList();
64 cg.addAnnotation(createSimpleVisibleAnnotation(cp));
65 cg.addAnnotation(createSimpleInvisibleAnnotation(cp));
67 buildClassContents(cg, cp, il);
69 dumpClass(cg, "HelloWorld.class");
71 JavaClass jc = getClassFrom(".", "HelloWorld");
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(
79 assertTrue("Name of annotation 2 should be SimpleAnnotation but it is " + as[1].getTypeName(), as[1].getTypeName().equals(
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()
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());
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
95 public void testGenerateMethodLevelAnnotations1() throws ClassNotFoundException {
97 ClassGen cg = createClassGen("HelloWorld");
98 ConstantPool cp = cg.getConstantPool();
99 InstructionList il = new InstructionList();
101 buildClassContentsWithAnnotatedMethods(cg, cp, il);
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);
107 dumpClass(cg, "temp1" + File.separator + "HelloWorld.class");
109 JavaClass jc2 = getClassFrom("temp1", "HelloWorld");
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);
115 ClassGen cg2 = new ClassGen(jc2);
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());
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);
127 assertTrue(wipe("temp1" + File.separator + "HelloWorld.class"));
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 !
135 public void testGenerateMethodLevelAnnotations2() throws ClassNotFoundException {
137 ClassGen cg = createClassGen("HelloWorld");
138 ConstantPool cp = cg.getConstantPool();
139 InstructionList il = new InstructionList();
141 buildClassContentsWithAnnotatedMethods(cg, cp, il);
143 dumpClass(cg, "temp2", "HelloWorld.class");
145 JavaClass jc2 = getClassFrom("temp2", "HelloWorld");
147 ClassGen cg2 = new ClassGen(jc2);
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);
154 MethodGen mainMethod2 = new MethodGen(mainMethod1, cg2.getClassName(), cg2.getConstantPool());
156 assertTrue("The 'MethodGen' should have one annotations but has " + mainMethod2.getAnnotations().size(), mainMethod2
157 .getAnnotations().size() == 1);
159 mainMethod2.addAnnotation(createFruitAnnotation(cg2.getConstantPool(), "Pear"));
161 cg2.removeMethod(mainMethod1);
162 cg2.addMethod(mainMethod2.getMethod());
164 dumpClass(cg2, "temp3", "HelloWorld.class");
166 JavaClass jc3 = getClassFrom("temp3", "HelloWorld");
168 ClassGen cg3 = new ClassGen(jc3);
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);
174 assertTrue(wipe("temp2", "HelloWorld.class"));
175 assertTrue(wipe("temp3", "HelloWorld.class"));
178 // J5TODO: Need to add deleteFile calls to many of these tests
181 * Transform simple class from an immutable to a mutable object.
183 public void testTransformClassToClassGen_SimpleTypes() throws ClassNotFoundException {
184 JavaClass jc = getClassFrom("testcode.jar", "SimpleAnnotatedClass");
185 ClassGen cgen = new ClassGen(jc);
187 // Check annotations are correctly preserved
188 AnnotationGen[] annotations = cgen.getAnnotations();
189 assertTrue("Expected one annotation but found " + annotations.length, annotations.length == 1);
193 * Transform simple class from an immutable to a mutable object. The class is annotated with an annotation that uses an enum.
195 public void testTransformClassToClassGen_EnumType() throws ClassNotFoundException {
196 JavaClass jc = getClassFrom("testcode.jar", "AnnotatedWithEnumClass");
197 ClassGen cgen = new ClassGen(jc);
199 // Check annotations are correctly preserved
200 AnnotationGen[] annotations = cgen.getAnnotations();
201 assertTrue("Expected one annotation but found " + annotations.length, annotations.length == 1);
205 * Transform simple class from an immutable to a mutable object. The class is annotated with an annotation that uses an array of
208 public void testTransformClassToClassGen_ArrayAndAnnotationTypes() throws ClassNotFoundException {
209 JavaClass jc = getClassFrom("testcode.jar", "AnnotatedWithCombinedAnnotation");
210 ClassGen cgen = new ClassGen(jc);
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;"));
232 * Transform complex class from an immutable to a mutable object.
234 public void testTransformComplexClassToClassGen() throws ClassNotFoundException {
235 JavaClass jc = getClassFrom("testcode.jar", "ComplexAnnotatedClass");
236 ClassGen cgen = new ClassGen(jc);
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 (NameValuePair element : l) {
244 if (element.getNameString().equals("dval")) {
245 if (((SimpleElementValue) element.getValue()).stringifyValue().equals("33.4"))
249 assertTrue("Did not find double annotation value with value 33.4", found);
253 * Load a class in and modify it with a new attribute - A SimpleAnnotation annotation
255 public void testModifyingClasses1() throws ClassNotFoundException {
256 JavaClass jc = getClassFrom("testcode.jar", "SimpleAnnotatedClass");
257 ClassGen cgen = new ClassGen(jc);
258 ConstantPool cp = cgen.getConstantPool();
259 cgen.addAnnotation(createFruitAnnotation(cp, "Pineapple"));
260 assertTrue("Should now have two annotations but has " + cgen.getAnnotations().length, cgen.getAnnotations().length == 2);
261 dumpClass(cgen, "SimpleAnnotatedClass.class");
262 assertTrue(wipe("SimpleAnnotatedClass.class"));
266 * Load a class in and modify it with a new attribute - A ComplexAnnotation annotation
268 public void testModifyingClasses2() throws ClassNotFoundException {
269 JavaClass jc = getClassFrom("testcode.jar", "SimpleAnnotatedClass");
270 ClassGen cgen = new ClassGen(jc);
271 ConstantPool cp = cgen.getConstantPool();
272 cgen.addAnnotation(createCombinedAnnotation(cp));
273 assertTrue("Should now have two annotations but has " + cgen.getAnnotations().length, cgen.getAnnotations().length == 2);
274 dumpClass(cgen, "SimpleAnnotatedClass.class");
275 JavaClass jc2 = getClassFrom(".", "SimpleAnnotatedClass");
276 jc2.getAnnotations();
277 assertTrue(wipe("SimpleAnnotatedClass.class"));
278 // System.err.println(jc2.toString());
281 private void dumpClass(ClassGen cg, String fname) {
283 File f = createTestdataFile(fname);
284 cg.getJavaClass().dump(f);
285 } catch (java.io.IOException e) {
286 System.err.println(e);
290 private void dumpClass(ClassGen cg, String dir, String fname) {
291 dumpClass(cg, dir + File.separator + fname);
294 private void buildClassContentsWithAnnotatedMethods(ClassGen cg, ConstantPool cp, InstructionList il) {
295 // Create method 'public static void main(String[]argv)'
296 MethodGen mg = createMethodGen("main", il, cp);
297 InstructionFactory factory = new InstructionFactory(cg);
298 mg.addAnnotation(createSimpleVisibleAnnotation(mg.getConstantPool()));
299 // We now define some often used types:
301 ObjectType i_stream = new ObjectType("java.io.InputStream");
302 ObjectType p_stream = new ObjectType("java.io.PrintStream");
304 // Create variables in and name : We call the constructors, i.e.,
305 // execute BufferedReader(InputStreamReader(System.in)) . The reference
306 // to the BufferedReader object stays on top of the stack and is stored
307 // in the newly allocated in variable.
309 il.append(factory.createNew("java.io.BufferedReader"));
310 il.append(InstructionConstants.DUP); // Use predefined constant
311 il.append(factory.createNew("java.io.InputStreamReader"));
312 il.append(InstructionConstants.DUP);
313 il.append(factory.createFieldAccess("java.lang.System", "in", i_stream, Constants.GETSTATIC));
314 il.append(factory.createInvoke("java.io.InputStreamReader", "<init>", Type.VOID, new Type[] { i_stream },
315 Constants.INVOKESPECIAL));
316 il.append(factory.createInvoke("java.io.BufferedReader", "<init>", Type.VOID,
317 new Type[] { new ObjectType("java.io.Reader") }, Constants.INVOKESPECIAL));
319 LocalVariableGen lg = mg.addLocalVariable("in", new ObjectType("java.io.BufferedReader"), null, null);
320 int in = lg.getIndex();
321 lg.setStart(il.append(InstructionFactory.createASTORE(in))); // "in" valid from here
323 // Create local variable name and initialize it to null
325 lg = mg.addLocalVariable("name", Type.STRING, null, null);
326 int name = lg.getIndex();
327 il.append(InstructionConstants.ACONST_NULL);
328 lg.setStart(il.append(InstructionFactory.createASTORE(name))); // "name" valid from here
330 // Create try-catch block: We remember the start of the block, read a
331 // line from the standard input and store it into the variable name .
333 // InstructionHandle try_start = il.append(factory.createFieldAccess(
334 // "java.lang.System", "out", p_stream, Constants.GETSTATIC));
336 // il.append(new PUSH(cp, "Please enter your name> "));
337 // il.append(factory.createInvoke("java.io.PrintStream", "print",
338 // Type.VOID, new Type[] { Type.STRING },
339 // Constants.INVOKEVIRTUAL));
340 // il.append(new ALOAD(in));
341 // il.append(factory.createInvoke("java.io.BufferedReader", "readLine",
342 // Type.STRING, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
343 InstructionHandle try_start = il.append(InstructionFactory.PUSH(cp, "Andy"));
344 il.append(InstructionFactory.createASTORE(name));
346 // Upon normal execution we jump behind exception handler, the target
347 // address is not known yet.
349 InstructionBranch g = new InstructionBranch(Constants.GOTO);
350 InstructionHandle try_end = il.append(g);
352 // We add the exception handler which simply returns from the method.
354 LocalVariableGen var_ex = mg.addLocalVariable("ex", Type.getType("Ljava.io.IOException;"), null, null);
355 int var_ex_slot = var_ex.getIndex();
357 InstructionHandle handler = il.append(InstructionFactory.createASTORE(var_ex_slot));
358 var_ex.setStart(handler);
359 var_ex.setEnd(il.append(InstructionConstants.RETURN));
361 mg.addExceptionHandler(try_start, try_end, handler, new ObjectType("java.io.IOException"));
363 // "Normal" code continues, now we can set the branch target of the GOTO
366 InstructionHandle ih = il.append(factory.createFieldAccess("java.lang.System", "out", p_stream, Constants.GETSTATIC));
369 // Printing "Hello": String concatenation compiles to StringBuffer
372 il.append(factory.createNew(Type.STRINGBUFFER));
373 il.append(InstructionConstants.DUP);
374 il.append(InstructionFactory.PUSH(cp, "Hello, "));
375 il.append(factory.createInvoke("java.lang.StringBuffer", "<init>", Type.VOID, new Type[] { Type.STRING },
376 Constants.INVOKESPECIAL));
377 il.append(InstructionFactory.createALOAD(name));
378 il.append(factory.createInvoke("java.lang.StringBuffer", "append", Type.STRINGBUFFER, new Type[] { Type.STRING },
379 Constants.INVOKEVIRTUAL));
380 il.append(factory.createInvoke("java.lang.StringBuffer", "toString", Type.STRING, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
382 il.append(factory.createInvoke("java.io.PrintStream", "println", Type.VOID, new Type[] { Type.STRING },
383 Constants.INVOKEVIRTUAL));
384 il.append(InstructionConstants.RETURN);
386 // Finalization: Finally, we have to set the stack size, which normally
387 // would have to be computed on the fly and add a default constructor
388 // method to the class, which is empty in this case.
392 cg.addMethod(mg.getMethod());
393 il.dispose(); // Allow instruction handles to be reused
394 cg.addEmptyConstructor(Constants.ACC_PUBLIC);
397 private void buildClassContents(ClassGen cg, ConstantPool cp, InstructionList il) {
398 // Create method 'public static void main(String[]argv)'
399 MethodGen mg = createMethodGen("main", il, cp);
400 InstructionFactory factory = new InstructionFactory(cg);
401 // We now define some often used types:
403 ObjectType i_stream = new ObjectType("java.io.InputStream");
404 ObjectType p_stream = new ObjectType("java.io.PrintStream");
406 // Create variables in and name : We call the constructors, i.e.,
407 // execute BufferedReader(InputStreamReader(System.in)) . The reference
408 // to the BufferedReader object stays on top of the stack and is stored
409 // in the newly allocated in variable.
411 il.append(factory.createNew("java.io.BufferedReader"));
412 il.append(InstructionConstants.DUP); // Use predefined constant
413 il.append(factory.createNew("java.io.InputStreamReader"));
414 il.append(InstructionConstants.DUP);
415 il.append(factory.createFieldAccess("java.lang.System", "in", i_stream, Constants.GETSTATIC));
416 il.append(factory.createInvoke("java.io.InputStreamReader", "<init>", Type.VOID, new Type[] { i_stream },
417 Constants.INVOKESPECIAL));
418 il.append(factory.createInvoke("java.io.BufferedReader", "<init>", Type.VOID,
419 new Type[] { new ObjectType("java.io.Reader") }, Constants.INVOKESPECIAL));
421 LocalVariableGen lg = mg.addLocalVariable("in", new ObjectType("java.io.BufferedReader"), null, null);
422 int in = lg.getIndex();
423 lg.setStart(il.append(InstructionFactory.createASTORE(in))); // "in" valid from here
425 // Create local variable name and initialize it to null
427 lg = mg.addLocalVariable("name", Type.STRING, null, null);
428 int name = lg.getIndex();
429 il.append(InstructionConstants.ACONST_NULL);
430 lg.setStart(il.append(InstructionFactory.createASTORE(name))); // "name" valid from here
432 // Create try-catch block: We remember the start of the block, read a
433 // line from the standard input and store it into the variable name .
435 // InstructionHandle try_start = il.append(factory.createFieldAccess(
436 // "java.lang.System", "out", p_stream, Constants.GETSTATIC));
438 // il.append(new PUSH(cp, "Please enter your name> "));
439 // il.append(factory.createInvoke("java.io.PrintStream", "print",
440 // Type.VOID, new Type[] { Type.STRING },
441 // Constants.INVOKEVIRTUAL));
442 // il.append(new ALOAD(in));
443 // il.append(factory.createInvoke("java.io.BufferedReader", "readLine",
444 // Type.STRING, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
445 InstructionHandle try_start = il.append(InstructionFactory.PUSH(cp, "Andy"));
446 il.append(InstructionFactory.createASTORE(name));
448 // Upon normal execution we jump behind exception handler, the target
449 // address is not known yet.
451 InstructionBranch g = new InstructionBranch(Constants.GOTO);
452 InstructionHandle try_end = il.append(g);
454 // We add the exception handler which simply returns from the method.
456 LocalVariableGen var_ex = mg.addLocalVariable("ex", Type.getType("Ljava.io.IOException;"), null, null);
457 int var_ex_slot = var_ex.getIndex();
459 InstructionHandle handler = il.append(InstructionFactory.createASTORE(var_ex_slot));
460 var_ex.setStart(handler);
461 var_ex.setEnd(il.append(InstructionConstants.RETURN));
463 mg.addExceptionHandler(try_start, try_end, handler, new ObjectType("java.io.IOException"));
465 // "Normal" code continues, now we can set the branch target of the GOTO
468 InstructionHandle ih = il.append(factory.createFieldAccess("java.lang.System", "out", p_stream, Constants.GETSTATIC));
471 // Printing "Hello": String concatenation compiles to StringBuffer
474 il.append(factory.createNew(Type.STRINGBUFFER));
475 il.append(InstructionConstants.DUP);
476 il.append(InstructionFactory.PUSH(cp, "Hello, "));
477 il.append(factory.createInvoke("java.lang.StringBuffer", "<init>", Type.VOID, new Type[] { Type.STRING },
478 Constants.INVOKESPECIAL));
479 il.append(InstructionFactory.createALOAD(name));
480 il.append(factory.createInvoke("java.lang.StringBuffer", "append", Type.STRINGBUFFER, new Type[] { Type.STRING },
481 Constants.INVOKEVIRTUAL));
482 il.append(factory.createInvoke("java.lang.StringBuffer", "toString", Type.STRING, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
484 il.append(factory.createInvoke("java.io.PrintStream", "println", Type.VOID, new Type[] { Type.STRING },
485 Constants.INVOKEVIRTUAL));
486 il.append(InstructionConstants.RETURN);
488 // Finalization: Finally, we have to set the stack size, which normally
489 // would have to be computed on the fly and add a default constructor
490 // method to the class, which is empty in this case.
494 cg.addMethod(mg.getMethod());
495 il.dispose(); // Allow instruction handles to be reused
496 cg.addEmptyConstructor(Constants.ACC_PUBLIC);
499 private JavaClass getClassFrom(String where, String clazzname) throws ClassNotFoundException {
500 SyntheticRepository repos = createRepos(where);
501 return repos.loadClass(clazzname);
506 private ClassGen createClassGen(String classname) {
507 return new ClassGen(classname, "java.lang.Object", "<generated>", Constants.ACC_PUBLIC | Constants.ACC_SUPER, null);
510 private MethodGen createMethodGen(String methodname, InstructionList il, ConstantPool cp) {
511 return new MethodGen(Constants.ACC_STATIC | Constants.ACC_PUBLIC, // access flags
512 Type.VOID, // return type
513 new Type[] { new ArrayType(Type.STRING, 1) }, // argument types
514 new String[] { "argv" }, // arg names
515 methodname, "HelloWorld", // method, class
519 public AnnotationGen createSimpleVisibleAnnotation(ConstantPool cp) {
520 SimpleElementValue evg = new SimpleElementValue(ElementValue.PRIMITIVE_INT, cp, 4);
522 NameValuePair nvGen = new NameValuePair("id", evg, cp);
524 ObjectType t = new ObjectType("SimpleAnnotation");
526 List<NameValuePair> elements = new ArrayList<>();
529 AnnotationGen a = new AnnotationGen(t, elements, true, cp);
533 public AnnotationGen createFruitAnnotation(ConstantPool cp, String aFruit) {
534 SimpleElementValue evg = new SimpleElementValue(ElementValue.STRING, cp, aFruit);
535 NameValuePair nvGen = new NameValuePair("fruit", evg, cp);
536 ObjectType t = new ObjectType("SimpleStringAnnotation");
537 List<NameValuePair> elements = new ArrayList<>();
539 return new AnnotationGen(t, elements, true, cp);
542 public AnnotationGen createCombinedAnnotation(ConstantPool cp) {
543 // Create an annotation instance
544 AnnotationGen a = createSimpleVisibleAnnotation(cp);
545 ArrayElementValue array = new ArrayElementValue(cp);
546 array.addElement(new AnnotationElementValue(a, cp));
547 NameValuePair nvp = new NameValuePair("value", array, cp);
548 List<NameValuePair> elements = new ArrayList<>();
550 return new AnnotationGen(new ObjectType("CombinedAnnotation"), elements, true, cp);
553 public AnnotationGen createSimpleInvisibleAnnotation(ConstantPool cp) {
554 SimpleElementValue evg = new SimpleElementValue(ElementValue.PRIMITIVE_INT, cp, 4);
556 NameValuePair nvGen = new NameValuePair("id", evg, cp);
558 ObjectType t = new ObjectType("SimpleAnnotation");
560 List<NameValuePair> elements = new ArrayList<>();
563 AnnotationGen a = new AnnotationGen(t, elements, false, cp);
567 protected void tearDown() throws Exception {