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 25KB

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