1 <html> 2 <head> 3 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> 4 <title>Javassist Tutorial</title> 5 <link rel="stylesheet" type="text/css" href="brown.css"> 6 </head> 7 8 <body> 9 10 <div align="right">Getting Started with Javassist</div> 11 12 <div align="left"><a href="tutorial2.html">Previous page</a></div> 13 14 <p> 15 <a href="#intro">5. Bytecode level API</a> 16 <ul> 17 <li><a href="#classfile">Obtaining a <code>ClassFile</code> object</a> 18 <br><li><a href="#member">Adding and removing a member</a> 19 <br><li><a href="#traverse">Traversing a method body</a> 20 <br><li><a href="#bytecode">Producing a bytecode sequence</a> 21 <br><li><a href="#annotation">Annotations (Meta tags)</a> 22 23 </ul> 24 25 <p><a href="#generics">6. Generics</a> 26 27 <p><a href="#varargs">7. Varargs</a> 28 29 <p><a href="#j2me">8. J2ME</a> 30 31 <p><br> 32 33 <a name="intro"> 34 <h2>5. Bytecode level API</h2> 35 36 <p> 37 Javassist also provides lower-level API for directly editing 38 a class file. To use this level of API, you need detailed 39 knowledge of the Java bytecode and the class file format 40 while this level of API allows you any kind of modification 41 of class files. 42 43 <p> 44 If you want to just produce a simple class file, 45 <code>javassist.bytecode.ClassFileWriter</code> might provide 46 the best API for you. It is much faster than 47 <code>javassist.bytecode.ClassFile</code> although its API 48 is minimum. 49 50 <a name="classfile"> 51 <h3>5.1 Obtaining a <code>ClassFile</code> object</h3> 52 53 <p>A <code>javassist.bytecode.ClassFile</code> object represents 54 a class file. To obtian this object, <code>getClassFile()</code> 55 in <code>CtClass</code> should be called. 56 57 <p>Otherwise, you can construct a 58 <code>javassist.bytecode.ClassFile</code> directly from a class file. 59 For example, 60 61 <ul><pre> 62 BufferedInputStream fin 63 = new BufferedInputStream(new FileInputStream("Point.class")); 64 ClassFile cf = new ClassFile(new DataInputStream(fin)); 65 </pre></ul> 66 67 <p> 68 This code snippet creats a <code>ClassFile</code> object from 69 <code>Point.class</code>. 70 71 <p> 72 A <code>ClassFile</code> object can be written back to a 73 class file. <code>write()</code> in <code>ClassFile</code> 74 writes the contents of the class file to a given 75 <code>DataOutputStream</code>. 76 77 <p><br> 78 79 <a name="member"> 80 <h3>5.2 Adding and removing a member</h3> 81 82 <p> 83 <code>ClassFile</code> provides <code>addField()</code> and 84 <code>addMethod()</code> for adding a field or a method (note that 85 a constructor is regarded as a method at the bytecode level). 86 It also provides <code>addAttribute()</code> for adding an attribute 87 to the class file. 88 89 <p> 90 Note that <code>FieldInfo</code>, <code>MethodInfo</code>, and 91 <code>AttributeInfo</code> objects include a link to a 92 <code>ConstPool</code> (constant pool table) object. The <code>ConstPool</code> 93 object must be common to the <code>ClassFile</code> object and 94 a <code>FieldInfo</code> (or <code>MethodInfo</code> etc.) object 95 that is added to that <code>ClassFile</code> object. 96 In other words, a <code>FieldInfo</code> (or <code>MethodInfo</code> etc.) object 97 must not be shared among different <code>ClassFile</code> objects. 98 99 <p> 100 To remove a field or a method from a <code>ClassFile</code> object, 101 you must first obtain a <code>java.util.List</code> 102 object containing all the fields of the class. <code>getFields()</code> 103 and <code>getMethods()</code> return the lists. A field or a method can 104 be removed by calling <code>remove()</code> on the <code>List</code> object. 105 An attribute can be removed in a similar way. 106 Call <code>getAttributes()</code> in <code>FieldInfo</code> or 107 <code>MethodInfo</code> to obtain the list of attributes, 108 and remove one from the list. 109 110 111 <p><br> 112 113 <a name="traverse"> 114 <h3>5.3 Traversing a method body</h3> 115 116 <p> 117 To examine every bytecode instruction in a method body, 118 <code>CodeIterator</code> is useful. To otbain this object, 119 do as follows: 120 121 <ul><pre> 122 ClassFile cf = ... ; 123 MethodInfo minfo = cf.getMethod("move"); // we assume move is not overloaded. 124 CodeAttribute ca = minfo.getCodeAttribute(); 125 CodeIterator i = ca.iterator(); 126 </pre></ul> 127 128 <p> 129 A <code>CodeIterator</code> object allows you to visit every 130 bytecode instruction one by one from the beginning to the end. 131 The following methods are part of the methods declared in 132 <code>CodeIterator</code>: 133 134 <ul> 135 <li><code>void begin()</code><br> 136 Move to the first instruction.<br> 137 <li><code>void move(int index)</code><br> 138 Move to the instruction specified by the given index.<br> 139 <li><code>boolean hasNext()</code><br> 140 Returns true if there is more instructions.<br> 141 <li><code>int next()</code><br> 142 Returns the index of the next instruction.<br> 143 <em>Note that it does not return the opcode of the next 144 instruction.</em><br> 145 <li><code>int byteAt(int index)</code><br> 146 Returns the unsigned 8bit value at the index.<br> 147 <li><code>int u16bitAt(int index)</code><br> 148 Returns the unsigned 16bit value at the index.<br> 149 <li><code>int write(byte[] code, int index)</code><br> 150 Writes a byte array at the index.<br> 151 <li><code>void insert(int index, byte[] code)</code><br> 152 Inserts a byte array at the index. 153 Branch offsets etc. are automatically adjusted.<br> 154 </ul> 155 156 <p>The following code snippet displays all the instructions included 157 in a method body: 158 159 <ul><pre> 160 CodeIterator ci = ... ; 161 while (ci.hasNext()) { 162 int index = ci.next(); 163 int op = ci.byteAt(index); 164 System.out.println(Mnemonic.OPCODE[op]); 165 } 166 </pre></ul> 167 168 <p><br> 169 170 <a name="bytecode"> 171 <h3>5.4 Producing a bytecode sequence</h3> 172 173 <p> 174 A <code>Bytecode</code> object represents a sequence of bytecode 175 instructions. It is a growable array of bytecode. 176 Here is a sample code snippet: 177 178 <ul><pre> 179 ConstPool cp = ...; // constant pool table 180 Bytecode b = new Bytecode(cp, 1, 0); 181 b.addIconst(3); 182 b.addReturn(CtClass.intType); 183 CodeAttribute ca = b.toCodeAttribute(); 184 </pre></ul> 185 186 <p> 187 This produces the code attribute representing the following sequence: 188 189 <ul><pre> 190 iconst_3 191 ireturn 192 </pre></ul> 193 194 <p> 195 You can also obtain a byte array containing this sequence by 196 calling <code>get()</code> in <code>Bytecode</code>. The 197 obtained array can be inserted in another code attribute. 198 199 <p> 200 While <code>Bytecode</code> provides a number of methods for adding a 201 specific instruction to the sequence, it provides 202 <code>addOpcode()</code> for adding an 8bit opcode and 203 <code>addIndex()</code> for adding an index. 204 The 8bit value of each opcode is defined in the <code>Opcode</code> 205 interface. 206 207 <p> 208 <code>addOpcode()</code> and other methods for adding a specific 209 instruction are automatically maintain the maximum stack depth 210 unless the control flow does not include a branch. 211 This value can be obtained by calling <code>getMaxStack()</code> 212 on the <code>Bytecode</code> object. 213 It is also reflected on the <code>CodeAttribute</code> object 214 constructed from the <code>Bytecode</code> object. 215 To recompute the maximum stack depth of a method body, 216 call <code>computeMaxStack()</code> in <code>CodeAttribute</code>. 217 218 <p><br> 219 220 <a name="annotation"> 221 <h3>5.5 Annotations (Meta tags)</h3> 222 223 <p>Annotations are stored in a class file 224 as runtime invisible (or visible) annotations attribute. 225 These attributes can be obtained from <code>ClassFile</code>, 226 <code>MethodInfo</code>, or <code>FieldInfo</code> objects. 227 Call <code>getAttribute(AnnotationsAttribute.invisibleTag)</code> 228 on those objects. For more details, see the javadoc manual 229 of <code>javassist.bytecode.AnnotationsAttribute</code> class 230 and the <code>javassist.bytecode.annotation</code> package. 231 232 <p>Javassist also let you access annotations by the higher-level 233 API. 234 If you want to access annotations through <code>CtClass</code>, 235 call <code>getAnnotations()</code> in <code>CtClass</code> or 236 <code>CtBehavior</code>. 237 238 <p><br> 239 240 <h2><a name="generics">6. Generics</a></h2> 241 242 <p>The lower-level API of Javassist fully supports generics 243 introduced by Java 5. On the other hand, the higher-level 244 API such as <code>CtClass</code> does not directly support 245 generics. However, this is not a serious problem for bytecode 246 transformation. 247 248 <p>The generics of Java is implemented by the erasure technique. 249 After compilation, all type parameters are dropped off. For 250 example, suppose that your source code declares a parameterized 251 type <code>Vector<String></code>: 252 253 <ul><pre> 254 Vector<String> v = new Vector<String>(); 255 : 256 String s = v.get(0); 257 </pre></ul> 258 259 <p>The compiled bytecode is equivalent to the following code: 260 261 <ul><pre> 262 Vector v = new Vector(); 263 : 264 String s = (String)v.get(0); 265 </pre></ul> 266 267 <p>So when you write a bytecode transformer, you can just drop 268 off all type parameters. For example, if you have a class: 269 270 <ul><pre> 271 public class Wrapper<T> { 272 T value; 273 public Wrapper(T t) { value = t; } 274 } 275 </pre></ul> 276 277 <p>and want to add an interface <code>Getter<T></code> to the 278 class <code>Wrapper<T></code>: 279 280 <ul><pre> 281 public interface Getter<T> { 282 T get(); 283 } 284 </pre></ul> 285 286 <p>Then the interface you really have to add is <code>Getter</code> 287 (the type parameters <code><T></code> drops off) 288 and the method you also have to add to the <code>Wrapper</code> 289 class is this simple one: 290 291 <ul><pre> 292 public Object get() { return value; } 293 </pre></ul> 294 295 <p>Note that no type parameters are necessary. 296 297 <p><br> 298 299 <h2><a name="varargs">7. Varargs</a></h2> 300 301 <p>Currently, Javassist does not directly support varargs. So to make a method with varargs, 302 you must explicitly set a method modifier. But this is easy. 303 Suppose that now you want to make the following method: 304 305 <ul><pre> 306 public int length(int... args) { return args.length; } 307 </pre></ul> 308 309 <p>The following code using Javassist will make the method shown above: 310 311 <ul><pre> 312 CtClass cc = /* target class */; 313 CtMethod m = CtMethod.make("public int length(int[] args) { return args.length; }", cc); 314 m.setModifiers(m.getModifiers() | Modifier.VARARGS); 315 cc.addMethod(m); 316 <pre></ul> 317 318 <p>The parameter type <code>int...</code> is changed into <code>int[]</code> 319 and <code>Modifier.VARARGS</code> is added to the method modifiers. 320 321 <p>To call this method, you must write: 322 323 <ul><pre> 324 length(new int[] { 1, 2, 3 }); 325 </pre></ul> 326 327 <p>instead of this method call using the varargs mechanism: 328 329 <ul><pre> 330 length(1, 2, 3); 331 </pre></ul> 332 333 <p><br> 334 335 <h2><a name="j2me">8. J2ME</a></h2> 336 337 <p>If you modify a class file for the J2ME execution environment, 338 you must perform <it>preverification</it>. Preverifying is basically 339 producing stack maps, which is similar to stack map tables introduced 340 into J2SE at JDK 1.6. Javassist maintains the stack maps for J2ME only if 341 <code>javassist.bytecode.MethodInfo.doPreverify</code> is true. 342 343 <p>You can also manually 344 produce a stack map for a modified method. 345 For a given method represented by a <code>CtMethod</code> object <code>m</code>, 346 you can produce a stack map by calling the following methods: 347 348 <ul><pre> 349 m.getMethodInfo().rebuildStackMapForME(cpool); 350 </pre></ul> 351 352 <p>Here, <code>cpool</code> is a <code>ClassPool</code> object, which is 353 available by calling <code>getClassPool()</code> on a <code>CtClass</code> 354 object. A <code>ClassPool</code> object is responsible for finding 355 class files from given class pathes. To obtain all the <code>CtMethod</code> 356 objects, call the <code>getDeclaredMethods</code> method on a <code>CtClass</code> object. 357 358 <p><br> 359 360 <a href="tutorial2.html">Previous page</a> 361 362 <hr> 363 Java(TM) is a trademark of Sun Microsystems, Inc.<br> 364 Copyright (C) 2000-2010 by Shigeru Chiba, All rights reserved. 365 </body> 366 </html> 367