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.

ParameterAnnotationsTest.java 24KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593
  1. /*******************************************************************************
  2. * Copyright (c) 2004 IBM All rights reserved. This program and the accompanying
  3. * materials are made available under the terms of the Common Public License
  4. * v1.0 which accompanies this distribution and is available at
  5. * http://www.eclipse.org/legal/cpl-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.List;
  13. import org.aspectj.apache.bcel.Constants;
  14. import org.aspectj.apache.bcel.classfile.Attribute;
  15. import org.aspectj.apache.bcel.classfile.JavaClass;
  16. import org.aspectj.apache.bcel.classfile.Method;
  17. import org.aspectj.apache.bcel.classfile.annotation.Annotation;
  18. import org.aspectj.apache.bcel.generic.ALOAD;
  19. import org.aspectj.apache.bcel.generic.ASTORE;
  20. import org.aspectj.apache.bcel.generic.ArrayType;
  21. import org.aspectj.apache.bcel.generic.ClassGen;
  22. import org.aspectj.apache.bcel.generic.ConstantPoolGen;
  23. import org.aspectj.apache.bcel.generic.GOTO;
  24. import org.aspectj.apache.bcel.generic.InstructionConstants;
  25. import org.aspectj.apache.bcel.generic.InstructionFactory;
  26. import org.aspectj.apache.bcel.generic.InstructionHandle;
  27. import org.aspectj.apache.bcel.generic.InstructionList;
  28. import org.aspectj.apache.bcel.generic.LocalVariableGen;
  29. import org.aspectj.apache.bcel.generic.MethodGen;
  30. import org.aspectj.apache.bcel.generic.ObjectType;
  31. import org.aspectj.apache.bcel.generic.PUSH;
  32. import org.aspectj.apache.bcel.generic.Type;
  33. import org.aspectj.apache.bcel.generic.annotation.AnnotationElementValueGen;
  34. import org.aspectj.apache.bcel.generic.annotation.AnnotationGen;
  35. import org.aspectj.apache.bcel.generic.annotation.ArrayElementValueGen;
  36. import org.aspectj.apache.bcel.generic.annotation.ElementNameValuePairGen;
  37. import org.aspectj.apache.bcel.generic.annotation.ElementValueGen;
  38. import org.aspectj.apache.bcel.generic.annotation.SimpleElementValueGen;
  39. import org.aspectj.apache.bcel.util.SyntheticRepository;
  40. /**
  41. * The program that some of the tests generate looks like this:
  42. public class HelloWorld {
  43. public static void main(String[] argv) {
  44. BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
  45. String name = null;
  46. try {
  47. name = "Andy";
  48. } catch(IOException e) { return; }
  49. System.out.println("Hello, " + name);
  50. }
  51. }
  52. *
  53. */
  54. public class ParameterAnnotationsTest extends BcelTestCase {
  55. protected void setUp() throws Exception {
  56. super.setUp();
  57. }
  58. /**
  59. * Programmatically construct a class and add an annotation to the main method parameter 'argv'
  60. */
  61. public void testParameterAnnotations_builtOK() {
  62. ClassGen clg = createClassGen("HelloWorld");
  63. ConstantPoolGen cpg = clg.getConstantPool();
  64. InstructionList il = new InstructionList();
  65. buildClassContentsWithAnnotatedMethods(clg,cpg,il,true);
  66. int i = clg.getMethods().length;
  67. assertTrue("Class should have 2 methods but has "+i,i==2);
  68. Method mainMethod = clg.getMethods()[0];
  69. Annotation[] annos = mainMethod.getAnnotationsOnParameter(0);
  70. assertTrue("Should be two annotation on the 'argv' parameter to main() but there are "+annos.length,annos.length==2);
  71. assertTrue("This annotation should contain the string 'fruit=Apples' but it is "+annos[0].toString(),
  72. annos[0].toString().indexOf("fruit=Apples")!=-1);
  73. assertTrue("This annotation should contain the string 'fruit=Oranges' but it is "+annos[1].toString(),
  74. annos[1].toString().indexOf("fruit=Oranges")!=-1);
  75. }
  76. /**
  77. * Check we can save and load a constructed class that contains parameter annotations
  78. */
  79. public void testParameterAnnotations_savedAndLoadedOK() throws ClassNotFoundException {
  80. ClassGen clg = createClassGen("HelloWorld");
  81. ConstantPoolGen cpg = clg.getConstantPool();
  82. InstructionList il = new InstructionList();
  83. buildClassContentsWithAnnotatedMethods(clg,cpg,il,true);
  84. dumpClass(clg,"temp5","HelloWorld.class");
  85. JavaClass jc = getClassFrom("temp5","HelloWorld");
  86. clg = new ClassGen(jc);
  87. int i = clg.getMethods().length;
  88. assertTrue("Class should have 2 methods but has "+i,i==2);
  89. Method mainMethod = clg.getMethods()[0];
  90. Annotation[] annos = mainMethod.getAnnotationsOnParameter(0);
  91. assertTrue("Should be two annotation on the 'argv' parameter to main() but there are "+annos.length,annos.length==2);
  92. assertTrue("This annotation should contain the string 'fruit=Apples' but it is "+annos[0].toString(),
  93. annos[0].toString().indexOf("fruit=Apples")!=-1);
  94. assertTrue("This annotation should contain the string 'fruit=Oranges' but it is "+annos[1].toString(),
  95. annos[1].toString().indexOf("fruit=Oranges")!=-1);
  96. assertTrue(wipe("temp5","HelloWorld.class"));
  97. }
  98. /*
  99. * Load an existing class, add new parameter annotations, save and then reload it
  100. */
  101. public void testParameterAnnotations_loadedThenModifiedThenSavedAndLoadedOK() throws ClassNotFoundException {
  102. JavaClass jc = getClassFrom("testcode.jar","AnnotatedParameters");
  103. ClassGen clg = new ClassGen(jc);
  104. ConstantPoolGen cpg = clg.getConstantPool();
  105. //
  106. // Foo method looks like this:
  107. // public void foo(@SimpleAnnotation(id=2) int arg1,
  108. // @SimpleAnnotation(id=3) @AnnotationEnumElement(enumval=SimpleEnum.Red) String arg2)
  109. Method m = findMethod(clg,"foo");
  110. assertTrue("Should be able to find method foo but couldn't",m!=null);
  111. /////////////////////// 1. Check the right number of annotations are there
  112. int i = m.getAnnotationsOnParameter(1).length;
  113. assertTrue("Should be two annotations on the second parameter but found: "+i,i==2);
  114. /////////////////////// 2. Let's add a new parameter annotation, a visible one, to the first parameter.
  115. // Build a modifiable version of the foo method
  116. MethodGen mg = new MethodGen(m,clg.getClassName(),cpg);
  117. // Check the annotations survived that transform
  118. i = mg.getAnnotationsOnParameter(1).size();
  119. assertTrue("Should be two annotations on the second parameter but found: "+i,i==2);
  120. // That worked, so let's add a new parameter annotation
  121. mg.addParameterAnnotation(0,createFruitAnnotation(cpg,"Banana",true));
  122. // Foo method should now look like this:
  123. // public void foo(@SimpleAnnotation(id=2) @SimpleStringAnnotation(fruit=Banana) int arg1,
  124. // @SimpleAnnotation(id=3) @AnnotationEnumElement(enumval=SimpleEnum.Red) String arg2)
  125. i = mg.getAnnotationsOnParameter(0).size();
  126. assertTrue("Should now be 2 parameter annotations but found "+i,i==2);
  127. i = mg.getAnnotationsOnParameter(0).get(1).toString().indexOf("fruit=Banana");
  128. assertTrue("Expected 'fruit=Banana' in the 2nd annotation on the first argument but got "+
  129. mg.getAnnotationsOnParameter(0).get(1).toString(),i!=-1);
  130. // delete the old method and add the new one
  131. clg.removeMethod(m);
  132. clg.addMethod(mg.getMethod());
  133. /////////////////////// 3. Dump it to disk
  134. dumpClass(clg,"temp2","AnnotatedParameters.class");
  135. /////////////////////// 4. Load it back in and verify the annotations persisted
  136. JavaClass jc2 = getClassFrom("temp2","AnnotatedParameters");
  137. m = jc2.getMethods()[2];
  138. Annotation[] p1annotations = m.getAnnotationsOnParameter(0);
  139. Annotation[] p2annotations = m.getAnnotationsOnParameter(1);
  140. assertTrue("Expected two annotations on the first parameter but found "+p1annotations.length,p1annotations.length==2);
  141. assertTrue("Expected two annotations on the second parameter but found "+p2annotations.length,p2annotations.length==2);
  142. String expectedString = "[@SimpleAnnotation(id=2),@SimpleStringAnnotation(fruit=Banana)]";
  143. assertTrue("Expected formatted short string of '"+expectedString+"' but it was '"+dumpAnnotations(p1annotations)+"'",
  144. dumpAnnotations(p1annotations).equals(expectedString));
  145. expectedString = "[@SimpleAnnotation(id=3),@AnnotationEnumElement(enumval=Red)]";
  146. assertTrue("Expected formatted short string of '"+expectedString+"' but it was '"+dumpAnnotations(p2annotations)+"'",
  147. dumpAnnotations(p2annotations).equals(expectedString));
  148. assertTrue(wipe("temp2","AnnotatedParameters.class"));
  149. }
  150. /**
  151. * same as above test but attaching invisible runtime parameter annotations
  152. */
  153. public void testParameterAnnotations_loadedThenModifiedWithInvisibleAnnotationThenSavedAndLoadedOK() throws ClassNotFoundException {
  154. JavaClass jc = getClassFrom("testcode.jar","AnnotatedParameters");
  155. ClassGen clg = new ClassGen(jc);
  156. ConstantPoolGen cpg = clg.getConstantPool();
  157. //
  158. // Foo method looks like this:
  159. // public void foo(@SimpleAnnotation(id=2) int arg1,
  160. // @SimpleAnnotation(id=3) @AnnotationEnumElement(enumval=SimpleEnum.Red) String arg2)
  161. Method m = findMethod(clg,"foo");
  162. assertTrue("Should be able to find method foo but couldn't",m!=null);
  163. /////////////////////// 1. Check the right number of annotations are there
  164. int i = m.getAnnotationsOnParameter(1).length;
  165. assertTrue("Should be two annotations on the second parameter but found: "+i,i==2);
  166. /////////////////////// 2. Let's add a new parameter annotation, a visible one, to the first parameter.
  167. // Build a modifiable version of the foo method
  168. MethodGen mg = new MethodGen(m,clg.getClassName(),cpg);
  169. // Check the annotations survived that transform
  170. i = mg.getAnnotationsOnParameter(1).size();
  171. assertTrue("Should be two annotations on the second parameter but found: "+i,i==2);
  172. // That worked, so let's add a new parameter annotation
  173. mg.addParameterAnnotation(0,createFruitAnnotation(cpg,"Banana",false));
  174. // Foo method should now look like this:
  175. // public void foo(@SimpleAnnotation(id=2) @SimpleStringAnnotation(fruit=Banana) int arg1,
  176. // @SimpleAnnotation(id=3) @AnnotationEnumElement(enumval=SimpleEnum.Red) String arg2)
  177. i = mg.getAnnotationsOnParameter(0).size();
  178. assertTrue("Should now be 2 parameter annotations but found "+i,i==2);
  179. i = mg.getAnnotationsOnParameter(0).get(1).toString().indexOf("fruit=Banana");
  180. assertTrue("Expected 'fruit=Banana' in the 2nd annotation on the first argument but got "+
  181. mg.getAnnotationsOnParameter(0).get(1).toString(),i!=-1);
  182. assertTrue("New annotation should be runtime invisible?",!((AnnotationGen)mg.getAnnotationsOnParameter(0).get(1)).isRuntimeVisible());
  183. // delete the old method and add the new one
  184. clg.removeMethod(m);
  185. clg.addMethod(mg.getMethod());
  186. /////////////////////// 3. Dump it to disk
  187. dumpClass(clg,"temp3","AnnotatedParameters.class");
  188. /////////////////////// 4. Load it back in and verify the annotations persisted
  189. JavaClass jc2 = getClassFrom("temp3","AnnotatedParameters");
  190. m = jc2.getMethods()[2];
  191. Annotation[] p1annotations = m.getAnnotationsOnParameter(0);
  192. Annotation[] p2annotations = m.getAnnotationsOnParameter(1);
  193. assertTrue("Expected two annotations on the first parameter but found "+p1annotations.length,p1annotations.length==2);
  194. assertTrue("Expected two annotations on the second parameter but found "+p2annotations.length,p2annotations.length==2);
  195. String expectedString = "[@SimpleAnnotation(id=2),@SimpleStringAnnotation(fruit=Banana)]";
  196. assertTrue("Expected formatted short string of '"+expectedString+"' but it was '"+dumpAnnotations(p1annotations)+"'",
  197. dumpAnnotations(p1annotations).equals(expectedString));
  198. expectedString = "[@SimpleAnnotation(id=3),@AnnotationEnumElement(enumval=Red)]";
  199. assertTrue("Expected formatted short string of '"+expectedString+"' but it was '"+dumpAnnotations(p2annotations)+"'",
  200. dumpAnnotations(p2annotations).equals(expectedString));
  201. assertTrue("Second annotation on first parameter should be runtime invisible?",
  202. !p1annotations[1].isRuntimeVisible());
  203. assertTrue(wipe("temp3","AnnotatedParameters.class"));
  204. // 5. Verify that when annotations for parameters are unpacked from attributes, the
  205. // attributes vanish !
  206. clg = new ClassGen(jc2);
  207. mg = new MethodGen(m,clg.getClassName(),clg.getConstantPool());
  208. Attribute[] as = mg.getAttributes();
  209. assertTrue("Should be 2 (RIPA and RVPA) but there are "+mg.getAttributes().length,mg.getAttributes().length==2);
  210. List l = mg.getAnnotationsOnParameter(0);
  211. assertTrue("Should be 2 annotations on first parameter but there is only "+l.size()+":"+l.toString(),
  212. l.size()==2);
  213. assertTrue("Should be 0 but there are "+mg.getAttributes().length,mg.getAttributes().length==0);
  214. }
  215. private Method findMethod(ClassGen c,String mname) {
  216. Method[] ms = c.getMethods();
  217. for (int i = 0; i < ms.length; i++) {
  218. if (ms[i].getName().equals(mname)) return ms[i];
  219. }
  220. return null;
  221. }
  222. private void dumpClass(ClassGen cg, String fname) {
  223. try {
  224. File f = createTestdataFile(fname);
  225. cg.getJavaClass().dump(f);
  226. } catch (java.io.IOException e) {
  227. System.err.println(e);
  228. }
  229. }
  230. private void dumpClass(ClassGen cg, String dir, String fname) {
  231. dumpClass(cg,dir+File.separator+fname);
  232. }
  233. private void buildClassContentsWithAnnotatedMethods(ClassGen cg, ConstantPoolGen cp, InstructionList il,boolean addParameterAnnotations) {
  234. // Create method 'public static void main(String[]argv)'
  235. MethodGen mg = createMethodGen("main",il,cp);
  236. InstructionFactory factory = new InstructionFactory(cg);
  237. mg.addAnnotation(createSimpleVisibleAnnotation(mg.getConstantPool()));
  238. // We now define some often used types:
  239. ObjectType i_stream = new ObjectType("java.io.InputStream");
  240. ObjectType p_stream = new ObjectType("java.io.PrintStream");
  241. // Create variables in and name : We call the constructors, i.e.,
  242. // execute BufferedReader(InputStreamReader(System.in)) . The reference
  243. // to the BufferedReader object stays on top of the stack and is stored
  244. // in the newly allocated in variable.
  245. il.append(factory.createNew("java.io.BufferedReader"));
  246. il.append(InstructionConstants.DUP); // Use predefined constant
  247. il.append(factory.createNew("java.io.InputStreamReader"));
  248. il.append(InstructionConstants.DUP);
  249. il.append(factory.createFieldAccess("java.lang.System", "in", i_stream,Constants.GETSTATIC));
  250. il.append(factory.createInvoke("java.io.InputStreamReader", "<init>",
  251. Type.VOID, new Type[] { i_stream }, Constants.INVOKESPECIAL));
  252. il.append(factory.createInvoke("java.io.BufferedReader", "<init>",
  253. Type.VOID, new Type[] { new ObjectType("java.io.Reader") },
  254. Constants.INVOKESPECIAL));
  255. LocalVariableGen lg = mg.addLocalVariable("in", new ObjectType(
  256. "java.io.BufferedReader"), null, null);
  257. int in = lg.getIndex();
  258. lg.setStart(il.append(new ASTORE(in))); // "in" valid from here
  259. // Create local variable name and initialize it to null
  260. lg = mg.addLocalVariable("name", Type.STRING, null, null);
  261. int name = lg.getIndex();
  262. il.append(InstructionConstants.ACONST_NULL);
  263. lg.setStart(il.append(new ASTORE(name))); // "name" valid from here
  264. // Create try-catch block: We remember the start of the block, read a
  265. // line from the standard input and store it into the variable name .
  266. // InstructionHandle try_start = il.append(factory.createFieldAccess(
  267. // "java.lang.System", "out", p_stream, Constants.GETSTATIC));
  268. // il.append(new PUSH(cp, "Please enter your name> "));
  269. // il.append(factory.createInvoke("java.io.PrintStream", "print",
  270. // Type.VOID, new Type[] { Type.STRING },
  271. // Constants.INVOKEVIRTUAL));
  272. // il.append(new ALOAD(in));
  273. // il.append(factory.createInvoke("java.io.BufferedReader", "readLine",
  274. // Type.STRING, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
  275. InstructionHandle try_start = il.append(new PUSH(cp,"Andy"));
  276. il.append(new ASTORE(name));
  277. // Upon normal execution we jump behind exception handler, the target
  278. // address is not known yet.
  279. GOTO g = new GOTO(null);
  280. InstructionHandle try_end = il.append(g);
  281. // We add the exception handler which simply returns from the method.
  282. LocalVariableGen var_ex = mg.addLocalVariable("ex",Type.getType("Ljava.io.IOException;"),null,null);
  283. int var_ex_slot = var_ex.getIndex();
  284. InstructionHandle handler = il.append(new ASTORE(var_ex_slot));
  285. var_ex.setStart(handler);
  286. var_ex.setEnd(il.append(InstructionConstants.RETURN));
  287. mg.addExceptionHandler(try_start, try_end, handler,
  288. new ObjectType("java.io.IOException"));
  289. // "Normal" code continues, now we can set the branch target of the GOTO
  290. // .
  291. InstructionHandle ih = il.append(factory.createFieldAccess(
  292. "java.lang.System", "out", p_stream, Constants.GETSTATIC));
  293. g.setTarget(ih);
  294. // Printing "Hello": String concatenation compiles to StringBuffer
  295. // operations.
  296. il.append(factory.createNew(Type.STRINGBUFFER));
  297. il.append(InstructionConstants.DUP);
  298. il.append(new PUSH(cp, "Hello, "));
  299. il
  300. .append(factory.createInvoke("java.lang.StringBuffer",
  301. "<init>", Type.VOID, new Type[] { Type.STRING },
  302. Constants.INVOKESPECIAL));
  303. il.append(new ALOAD(name));
  304. il.append(factory.createInvoke("java.lang.StringBuffer", "append",
  305. Type.STRINGBUFFER, new Type[] { Type.STRING },
  306. Constants.INVOKEVIRTUAL));
  307. il.append(factory.createInvoke("java.lang.StringBuffer", "toString",
  308. Type.STRING, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
  309. il.append(factory.createInvoke("java.io.PrintStream", "println",
  310. 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.addParameterAnnotation(0,createFruitAnnotation(cp,"Apples",true));
  317. mg.addParameterAnnotation(0,createFruitAnnotation(cp,"Oranges",true));
  318. mg.setMaxStack();
  319. mg.setMaxLocals();
  320. cg.addMethod(mg.getMethod());
  321. il.dispose(); // Allow instruction handles to be reused
  322. cg.addEmptyConstructor(Constants.ACC_PUBLIC);
  323. }
  324. private void buildClassContents(ClassGen cg, ConstantPoolGen cp, InstructionList il) {
  325. // Create method 'public static void main(String[]argv)'
  326. MethodGen mg = createMethodGen("main",il,cp);
  327. InstructionFactory factory = new InstructionFactory(cg);
  328. // We now define some often used types:
  329. ObjectType i_stream = new ObjectType("java.io.InputStream");
  330. ObjectType p_stream = new ObjectType("java.io.PrintStream");
  331. // Create variables in and name : We call the constructors, i.e.,
  332. // execute BufferedReader(InputStreamReader(System.in)) . The reference
  333. // to the BufferedReader object stays on top of the stack and is stored
  334. // in the newly allocated in variable.
  335. il.append(factory.createNew("java.io.BufferedReader"));
  336. il.append(InstructionConstants.DUP); // Use predefined constant
  337. il.append(factory.createNew("java.io.InputStreamReader"));
  338. il.append(InstructionConstants.DUP);
  339. il.append(factory.createFieldAccess("java.lang.System", "in", i_stream,Constants.GETSTATIC));
  340. il.append(factory.createInvoke("java.io.InputStreamReader", "<init>",
  341. Type.VOID, new Type[] { i_stream }, Constants.INVOKESPECIAL));
  342. il.append(factory.createInvoke("java.io.BufferedReader", "<init>",
  343. Type.VOID, new Type[] { new ObjectType("java.io.Reader") },
  344. Constants.INVOKESPECIAL));
  345. LocalVariableGen lg = mg.addLocalVariable("in", new ObjectType(
  346. "java.io.BufferedReader"), null, null);
  347. int in = lg.getIndex();
  348. lg.setStart(il.append(new ASTORE(in))); // "in" valid from here
  349. // Create local variable name and initialize it to null
  350. lg = mg.addLocalVariable("name", Type.STRING, null, null);
  351. int name = lg.getIndex();
  352. il.append(InstructionConstants.ACONST_NULL);
  353. lg.setStart(il.append(new ASTORE(name))); // "name" valid from here
  354. // Create try-catch block: We remember the start of the block, read a
  355. // line from the standard input and store it into the variable name .
  356. // InstructionHandle try_start = il.append(factory.createFieldAccess(
  357. // "java.lang.System", "out", p_stream, Constants.GETSTATIC));
  358. // il.append(new PUSH(cp, "Please enter your name> "));
  359. // il.append(factory.createInvoke("java.io.PrintStream", "print",
  360. // Type.VOID, new Type[] { Type.STRING },
  361. // Constants.INVOKEVIRTUAL));
  362. // il.append(new ALOAD(in));
  363. // il.append(factory.createInvoke("java.io.BufferedReader", "readLine",
  364. // Type.STRING, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
  365. InstructionHandle try_start = il.append(new PUSH(cp,"Andy"));
  366. il.append(new ASTORE(name));
  367. // Upon normal execution we jump behind exception handler, the target
  368. // address is not known yet.
  369. GOTO g = new GOTO(null);
  370. InstructionHandle try_end = il.append(g);
  371. // We add the exception handler which simply returns from the method.
  372. LocalVariableGen var_ex = mg.addLocalVariable("ex",Type.getType("Ljava.io.IOException;"),null,null);
  373. int var_ex_slot = var_ex.getIndex();
  374. InstructionHandle handler = il.append(new ASTORE(var_ex_slot));
  375. var_ex.setStart(handler);
  376. var_ex.setEnd(il.append(InstructionConstants.RETURN));
  377. mg.addExceptionHandler(try_start, try_end, handler,
  378. new ObjectType("java.io.IOException"));
  379. // "Normal" code continues, now we can set the branch target of the GOTO
  380. // .
  381. InstructionHandle ih = il.append(factory.createFieldAccess(
  382. "java.lang.System", "out", p_stream, Constants.GETSTATIC));
  383. g.setTarget(ih);
  384. // Printing "Hello": String concatenation compiles to StringBuffer
  385. // operations.
  386. il.append(factory.createNew(Type.STRINGBUFFER));
  387. il.append(InstructionConstants.DUP);
  388. il.append(new PUSH(cp, "Hello, "));
  389. il
  390. .append(factory.createInvoke("java.lang.StringBuffer",
  391. "<init>", Type.VOID, new Type[] { Type.STRING },
  392. Constants.INVOKESPECIAL));
  393. il.append(new ALOAD(name));
  394. il.append(factory.createInvoke("java.lang.StringBuffer", "append",
  395. Type.STRINGBUFFER, new Type[] { Type.STRING },
  396. Constants.INVOKEVIRTUAL));
  397. il.append(factory.createInvoke("java.lang.StringBuffer", "toString",
  398. Type.STRING, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
  399. il.append(factory.createInvoke("java.io.PrintStream", "println",
  400. Type.VOID, new Type[] { Type.STRING },
  401. Constants.INVOKEVIRTUAL));
  402. il.append(InstructionConstants.RETURN);
  403. // Finalization: Finally, we have to set the stack size, which normally
  404. // would have to be computed on the fly and add a default constructor
  405. // method to the class, which is empty in this case.
  406. mg.setMaxStack();
  407. mg.setMaxLocals();
  408. cg.addMethod(mg.getMethod());
  409. il.dispose(); // Allow instruction handles to be reused
  410. cg.addEmptyConstructor(Constants.ACC_PUBLIC);
  411. }
  412. private JavaClass getClassFrom(String where,String clazzname) throws ClassNotFoundException {
  413. SyntheticRepository repos = createRepos(where);
  414. return repos.loadClass(clazzname);
  415. }
  416. // helper methods
  417. private ClassGen createClassGen(String classname) {
  418. return new ClassGen(classname, "java.lang.Object",
  419. "<generated>", Constants.ACC_PUBLIC | Constants.ACC_SUPER, null);
  420. }
  421. private MethodGen createMethodGen(String methodname,InstructionList il,ConstantPoolGen cp) {
  422. return new MethodGen(
  423. Constants.ACC_STATIC | Constants.ACC_PUBLIC, // access flags
  424. Type.VOID, // return type
  425. new Type[] { new ArrayType(Type.STRING, 1) }, // argument types
  426. new String[] { "argv" }, // arg names
  427. methodname, "HelloWorld", // method, class
  428. il, cp);
  429. }
  430. public AnnotationGen createSimpleVisibleAnnotation(ConstantPoolGen cp) {
  431. SimpleElementValueGen evg = new SimpleElementValueGen(
  432. ElementValueGen.PRIMITIVE_INT, cp, 4);
  433. ElementNameValuePairGen nvGen = new ElementNameValuePairGen("id", evg,cp);
  434. ObjectType t = new ObjectType("SimpleAnnotation");
  435. List elements = new ArrayList();
  436. elements.add(nvGen);
  437. AnnotationGen a = new AnnotationGen(t, elements,true, cp);
  438. return a;
  439. }
  440. public AnnotationGen createCombinedAnnotation(ConstantPoolGen cp) {
  441. // Create an annotation instance
  442. AnnotationGen a = createSimpleVisibleAnnotation(cp);
  443. ArrayElementValueGen array = new ArrayElementValueGen(cp);
  444. array.addElement(new AnnotationElementValueGen(a,cp));
  445. ElementNameValuePairGen nvp = new ElementNameValuePairGen("value",array,cp);
  446. List elements = new ArrayList();
  447. elements.add(nvp);
  448. return new AnnotationGen(new ObjectType("CombinedAnnotation"),elements,true,cp);
  449. }
  450. public AnnotationGen createSimpleInvisibleAnnotation(ConstantPoolGen cp) {
  451. SimpleElementValueGen evg = new SimpleElementValueGen(
  452. ElementValueGen.PRIMITIVE_INT, cp, 4);
  453. ElementNameValuePairGen nvGen = new ElementNameValuePairGen("id", evg,cp);
  454. ObjectType t = new ObjectType("SimpleAnnotation");
  455. List elements = new ArrayList();
  456. elements.add(nvGen);
  457. AnnotationGen a = new AnnotationGen(t, elements,false, cp);
  458. return a;
  459. }
  460. protected void tearDown() throws Exception {
  461. super.tearDown();
  462. }
  463. }