Home | History | Annotate | Download | only in tutorial
      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&lt;String&gt;</code>:
    252 
    253 <ul><pre>
    254 Vector&lt;String&gt; v = new Vector&lt;String&gt();
    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&lt;T&gt; {
    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&lt;T&gt;</code> to the
    278 class <code>Wrapper&lt;T&gt;</code>:
    279 
    280 <ul><pre>
    281 public interface Getter&lt;T&gt; {
    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>&lt;T&gt;</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