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> 37Javassist also provides lower-level API for directly editing 38a class file. To use this level of API, you need detailed 39knowledge of the Java bytecode and the class file format 40while this level of API allows you any kind of modification 41of class files. 42 43<p> 44If you want to just produce a simple class file, 45<code>javassist.bytecode.ClassFileWriter</code> might provide 46the best API for you. It is much faster than 47<code>javassist.bytecode.ClassFile</code> although its API 48is 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 54a class file. To obtian this object, <code>getClassFile()</code> 55in <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. 59For example, 60 61<ul><pre> 62BufferedInputStream fin 63 = new BufferedInputStream(new FileInputStream("Point.class")); 64ClassFile cf = new ClassFile(new DataInputStream(fin)); 65</pre></ul> 66 67<p> 68This code snippet creats a <code>ClassFile</code> object from 69<code>Point.class</code>. 70 71<p> 72A <code>ClassFile</code> object can be written back to a 73class file. <code>write()</code> in <code>ClassFile</code> 74writes 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 85a constructor is regarded as a method at the bytecode level). 86It also provides <code>addAttribute()</code> for adding an attribute 87to the class file. 88 89<p> 90Note 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> 93object must be common to the <code>ClassFile</code> object and 94a <code>FieldInfo</code> (or <code>MethodInfo</code> etc.) object 95that is added to that <code>ClassFile</code> object. 96In other words, a <code>FieldInfo</code> (or <code>MethodInfo</code> etc.) object 97must not be shared among different <code>ClassFile</code> objects. 98 99<p> 100To remove a field or a method from a <code>ClassFile</code> object, 101you must first obtain a <code>java.util.List</code> 102object containing all the fields of the class. <code>getFields()</code> 103and <code>getMethods()</code> return the lists. A field or a method can 104be removed by calling <code>remove()</code> on the <code>List</code> object. 105An attribute can be removed in a similar way. 106Call <code>getAttributes()</code> in <code>FieldInfo</code> or 107<code>MethodInfo</code> to obtain the list of attributes, 108and 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> 117To examine every bytecode instruction in a method body, 118<code>CodeIterator</code> is useful. To otbain this object, 119do as follows: 120 121<ul><pre> 122ClassFile cf = ... ; 123MethodInfo minfo = cf.getMethod("move"); // we assume move is not overloaded. 124CodeAttribute ca = minfo.getCodeAttribute(); 125CodeIterator i = ca.iterator(); 126</pre></ul> 127 128<p> 129A <code>CodeIterator</code> object allows you to visit every 130bytecode instruction one by one from the beginning to the end. 131The following methods are part of the methods declared in 132<code>CodeIterator</code>: 133 134<ul> 135<li><code>void begin()</code><br> 136Move to the first instruction.<br> 137<li><code>void move(int index)</code><br> 138Move to the instruction specified by the given index.<br> 139<li><code>boolean hasNext()</code><br> 140Returns true if there is more instructions.<br> 141<li><code>int next()</code><br> 142Returns the index of the next instruction.<br> 143<em>Note that it does not return the opcode of the next 144instruction.</em><br> 145<li><code>int byteAt(int index)</code><br> 146Returns the unsigned 8bit value at the index.<br> 147<li><code>int u16bitAt(int index)</code><br> 148Returns the unsigned 16bit value at the index.<br> 149<li><code>int write(byte[] code, int index)</code><br> 150Writes a byte array at the index.<br> 151<li><code>void insert(int index, byte[] code)</code><br> 152Inserts a byte array at the index. 153Branch offsets etc. are automatically adjusted.<br> 154</ul> 155 156<p>The following code snippet displays all the instructions included 157in a method body: 158 159<ul><pre> 160CodeIterator ci = ... ; 161while (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> 174A <code>Bytecode</code> object represents a sequence of bytecode 175instructions. It is a growable array of bytecode. 176Here is a sample code snippet: 177 178<ul><pre> 179ConstPool cp = ...; // constant pool table 180Bytecode b = new Bytecode(cp, 1, 0); 181b.addIconst(3); 182b.addReturn(CtClass.intType); 183CodeAttribute ca = b.toCodeAttribute(); 184</pre></ul> 185 186<p> 187This produces the code attribute representing the following sequence: 188 189<ul><pre> 190iconst_3 191ireturn 192</pre></ul> 193 194<p> 195You can also obtain a byte array containing this sequence by 196calling <code>get()</code> in <code>Bytecode</code>. The 197obtained array can be inserted in another code attribute. 198 199<p> 200While <code>Bytecode</code> provides a number of methods for adding a 201specific instruction to the sequence, it provides 202<code>addOpcode()</code> for adding an 8bit opcode and 203<code>addIndex()</code> for adding an index. 204The 8bit value of each opcode is defined in the <code>Opcode</code> 205interface. 206 207<p> 208<code>addOpcode()</code> and other methods for adding a specific 209instruction are automatically maintain the maximum stack depth 210unless the control flow does not include a branch. 211This value can be obtained by calling <code>getMaxStack()</code> 212on the <code>Bytecode</code> object. 213It is also reflected on the <code>CodeAttribute</code> object 214constructed from the <code>Bytecode</code> object. 215To recompute the maximum stack depth of a method body, 216call <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 224as runtime invisible (or visible) annotations attribute. 225These attributes can be obtained from <code>ClassFile</code>, 226<code>MethodInfo</code>, or <code>FieldInfo</code> objects. 227Call <code>getAttribute(AnnotationsAttribute.invisibleTag)</code> 228on those objects. For more details, see the javadoc manual 229of <code>javassist.bytecode.AnnotationsAttribute</code> class 230and the <code>javassist.bytecode.annotation</code> package. 231 232<p>Javassist also let you access annotations by the higher-level 233API. 234If you want to access annotations through <code>CtClass</code>, 235call <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 243introduced by Java 5. On the other hand, the higher-level 244API such as <code>CtClass</code> does not directly support 245generics. However, this is not a serious problem for bytecode 246transformation. 247 248<p>The generics of Java is implemented by the erasure technique. 249After compilation, all type parameters are dropped off. For 250example, suppose that your source code declares a parameterized 251type <code>Vector<String></code>: 252 253<ul><pre> 254Vector<String> v = new Vector<String>(); 255 : 256String s = v.get(0); 257</pre></ul> 258 259<p>The compiled bytecode is equivalent to the following code: 260 261<ul><pre> 262Vector v = new Vector(); 263 : 264String s = (String)v.get(0); 265</pre></ul> 266 267<p>So when you write a bytecode transformer, you can just drop 268off all type parameters. For example, if you have a class: 269 270<ul><pre> 271public 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 278class <code>Wrapper<T></code>: 279 280<ul><pre> 281public 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) 288and the method you also have to add to the <code>Wrapper</code> 289class is this simple one: 290 291<ul><pre> 292public 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, 302you must explicitly set a method modifier. But this is easy. 303Suppose that now you want to make the following method: 304 305<ul><pre> 306public 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> 312CtClass cc = /* target class */; 313CtMethod m = CtMethod.make("public int length(int[] args) { return args.length; }", cc); 314m.setModifiers(m.getModifiers() | Modifier.VARARGS); 315cc.addMethod(m); 316<pre></ul> 317 318<p>The parameter type <code>int...</code> is changed into <code>int[]</code> 319and <code>Modifier.VARARGS</code> is added to the method modifiers. 320 321<p>To call this method, you must write: 322 323<ul><pre> 324length(new int[] { 1, 2, 3 }); 325</pre></ul> 326 327<p>instead of this method call using the varargs mechanism: 328 329<ul><pre> 330length(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, 338you must perform <it>preverification</it>. Preverifying is basically 339producing stack maps, which is similar to stack map tables introduced 340into 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 344produce a stack map for a modified method. 345For a given method represented by a <code>CtMethod</code> object <code>m</code>, 346you can produce a stack map by calling the following methods: 347 348<ul><pre> 349m.getMethodInfo().rebuildStackMapForME(cpool); 350</pre></ul> 351 352<p>Here, <code>cpool</code> is a <code>ClassPool</code> object, which is 353available by calling <code>getClassPool()</code> on a <code>CtClass</code> 354object. A <code>ClassPool</code> object is responsible for finding 355class files from given class pathes. To obtain all the <code>CtMethod</code> 356objects, 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> 363Java(TM) is a trademark of Sun Microsystems, Inc.<br> 364Copyright (C) 2000-2010 by Shigeru Chiba, All rights reserved. 365</body> 366</html> 367