• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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&lt;String&gt;</code>:
252
253<ul><pre>
254Vector&lt;String&gt; v = new Vector&lt;String&gt();
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&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
278class <code>Wrapper&lt;T&gt;</code>:
279
280<ul><pre>
281public 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)
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