You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

GeneratingAnnotatedClassesTest.java 24KB

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