• 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<body>
8
9<b>
10<font size="+3">
11Getting Started with Javassist
12</font>
13
14<p><font size="+2">
15Shigeru Chiba
16</font>
17</b>
18
19<p><div align="right"><a href="tutorial2.html">Next page</a></div>
20
21<ul>1. <a href="#read">Reading and writing bytecode</a>
22<br>2. <a href="#pool">ClassPool</a>
23<br>3. <a href="#load">Class loader</a>
24<br>4. <a href="tutorial2.html#intro">Introspection and customization</a>
25<br>5. <a href="tutorial3.html#intro">Bytecode level API</a>
26<br>6. <a href="tutorial3.html#generics">Generics</a>
27<br>7. <a href="tutorial3.html#varargs">Varargs</a>
28<br>8. <a href="tutorial3.html#j2me">J2ME</a>
29</ul>
30
31<p><br>
32
33<a name="read">
34<h2>1. Reading and writing bytecode</h2>
35
36<p>Javassist is a class library for dealing with Java bytecode.
37Java bytecode is stored in a binary file called a class file.
38Each class file contains one Java class or interface.
39
40<p>The class <code>Javassist.CtClass</code> is an absatract
41representation of a class file.  A <code>CtClass</code> (compile-time
42class) object is a handle for dealing with a class file.  The
43following program is a very simple example:
44
45<ul><pre>
46ClassPool pool = ClassPool.getDefault();
47CtClass cc = pool.get("test.Rectangle");
48cc.setSuperclass(pool.get("test.Point"));
49cc.writeFile();
50</pre></ul>
51
52<p>This program first obtains a <code>ClassPool</code> object, which
53controls bytecode modification with Javassist.  The
54<code>ClassPool</code> object is a container of <code>CtClass</code>
55object representing a class file.  It reads a class file on demand for
56constructing a <code>CtClass</code> object and records the
57constructed object for responding later accesses.
58
59To modify the definition of a class, the users must first obtain
60from a <code>ClassPool</code> object
61a reference to a <code>CtClass</code> object representing that class.
62<code>get()</code> in <code>ClassPool</code> is used for this purpose.
63In the case of the program shown above, the
64<code>CtClass</code> object representing a class
65<code>test.Rectangle</code> is obtained from the
66<code>ClassPool</code> object and it is assigned to a variable
67<code>cc</code>.
68The <code>ClassPool</code> object returned by <code>getDfault()</code>
69searches the default system search path.
70
71<p>From the implementation viewpoint, <code>ClassPool</code> is a hash
72table of <code>CtClass</code> objects, which uses the class names as
73keys.  <code>get()</code> in <code>ClassPool</code> searches this hash
74table to find a <code>CtClass</code> object associated with the
75specified key.  If such a <code>CtClass</code> object is not found,
76<code>get()</code> reads a class file to construct a new
77<code>CtClass</code> object, which is recorded in the hash table and
78then returned as the resulting value of <code>get()</code>.
79
80<p>The <code>CtClass</code> object obtained from a <code>ClassPool</code>
81object can be modified
82(<a href="tutorial2.html#intro">details of how to modify
83a <code>CtClass</code></a> will be presented later).
84In the example above, it is modified so that the superclass of
85<code>test.Rectangle</code> is changed into a class
86<code>test.Point</code>.  This change is reflected on the original
87class file when <code>writeFile()</code> in <code>CtClass()</code> is
88finally called.
89
90<p><code>writeFile()</code> translates the <code>CtClass</code> object
91into a class file and writes it on a local disk.
92Javassist also provides a method for directly obtaining the
93modified bytecode.  To obtain the bytecode, call <code>toBytecode()</code>:
94
95<ul><pre>
96byte[] b = cc.toBytecode();
97</pre></ul>
98
99<p>You can directly load the <code>CtClass</code> as well:
100
101<ul><pre>
102Class clazz = cc.toClass();
103</pre></ul>
104
105<p><code>toClass()</code> requests the context class loader for the current
106thread to load the class file represented by the <code>CtClass</code>.  It
107returns a <code>java.lang.Class</code> object representing the loaded class.
108For more details, please see <a href="#toclass">this section below</a>.
109
110<a name="def">
111<h4>Defining a new class</h4>
112
113<p>To define a new class from scratch, <code>makeClass()</code>
114must be called on a <code>ClassPool</code>.
115
116<ul><pre>
117ClassPool pool = ClassPool.getDefault();
118CtClass cc = pool.makeClass("Point");
119</pre></ul>
120
121<p>This program defines a class <code>Point</code>
122including no members.
123Member methods of <code>Point</code> can be created with
124factory methods declared in <code>CtNewMethod</code> and
125appended to <code>Point</code> with <code>addMethod()</code>
126in <code>CtClass</code>.
127
128<p><code>makeClass()</code> cannot create a new interface;
129<code>makeInterface()</code> in <code>ClassPool</code> can do.
130Member methods in an interface can be created with
131<code>abstractMethod()</code> in <code>CtNewMethod</code>.
132Note that an interface method is an abstract method.
133
134<a name="frozenclasses">
135<h4>Frozen classes</h4></a>
136
137<p>If a <code>CtClass</code> object is converted into a class file by
138<code>writeFile()</code>, <code>toClass()</code>, or
139<code>toBytecode()</code>, Javassist freezes that <code>CtClass</code>
140object.  Further modifications of that <code>CtClass</code> object are
141not permitted.  This is for warning the developers when they attempt
142to modify a class file that has been already loaded since the JVM does
143not allow reloading a class.
144
145<p>A frozen <code>CtClass</code> can be defrost so that
146modifications of the class definition will be permitted.  For example,
147
148<ul><pre>
149CtClasss cc = ...;
150    :
151cc.writeFile();
152cc.defrost();
153cc.setSuperclass(...);    // OK since the class is not frozen.
154</pre></ul>
155
156<p>After <code>defrost()</code> is called, the <code>CtClass</code>
157object can be modified again.
158
159<p>If <code>ClassPool.doPruning</code> is set to <code>true</code>,
160then Javassist prunes the data structure contained
161in a <code>CtClass</code> object
162when Javassist freezes that object.
163To reduce memory
164consumption, pruning discards unnecessary attributes
165(<code>attribute_info</code> structures) in that object.
166For example, <code>Code_attribute</code> structures (method bodies)
167are discarded.
168Thus, after a
169<code>CtClass</code> object is pruned, the bytecode of a method is not
170accessible except method names, signatures, and annotations.
171The pruned <code>CtClass</code> object cannot be defrost again.
172The default value of <code>ClassPool.doPruning</code> is <code>false</code>.
173
174<p>To disallow pruning a particular <code>CtClass</code>,
175<code>stopPruning()</code> must be called on that object in advance:
176
177<ul><pre>
178CtClasss cc = ...;
179cc.stopPruning(true);
180    :
181cc.writeFile();                             // convert to a class file.
182// cc is not pruned.
183</pre></ul>
184
185<p>The <code>CtClass</code> object <code>cc</code> is not pruned.
186Thus it can be defrost after <code>writeFile()</code> is called.
187
188<ul><b>Note:</b>
189While debugging, you might want to temporarily stop pruning and freezing
190and write a modified class file to a disk drive.
191<code>debugWriteFile()</code> is a convenient method
192for that purpose.  It stops pruning, writes a class file, defrosts it,
193and turns pruning on again (if it was initially on).
194</ul>
195
196
197
198<h4>Class search path</h4>
199
200<p>The default <code>ClassPool</code> returned
201by a static method <code>ClassPool.getDefault()</code>
202searches the same path that the underlying JVM (Java virtual machine) has.
203<em>If a program is running on a web application server such as JBoss and Tomcat,
204the <code>ClassPool</code> object may not be able to find user classes</em>
205since such a web application server uses multiple class loaders as well as
206the system class loader.  In that case, an additional class path must be
207registered to the <code>ClassPool</code>.  Suppose that <code>pool</code>
208refers to a <code>ClassPool</code> object:
209
210<ul><pre>
211pool.insertClassPath(new ClassClassPath(this.getClass()));
212</pre></ul>
213
214<p>
215This statement registers the class path that was used for loading
216the class of the object that <code>this</code> refers to.
217You can use any <code>Class</code> object as an argument instead of
218<code>this.getClass()</code>.  The class path used for loading the
219class represented by that <code>Class</code> object is registered.
220
221<p>
222You can register a directory name as the class search path.
223For example, the following code adds a directory
224<code>/usr/local/javalib</code>
225to the search path:
226
227<ul><pre>
228ClassPool pool = ClassPool.getDefault();
229pool.insertClassPath("/usr/local/javalib");
230</pre></ul>
231
232<p>The search path that the users can add is not only a directory but also
233a URL:
234
235<ul><pre>
236ClassPool pool = ClassPool.getDefault();
237ClassPath cp = new URLClassPath("www.javassist.org", 80, "/java/", "org.javassist.");
238pool.insertClassPath(cp);
239</pre></ul>
240
241<p>This program adds "http://www.javassist.org:80/java/" to the class search
242path.  This URL is used only for searching classes belonging to a
243package <code>org.javassist</code>.  For example, to load a class
244<code>org.javassist.test.Main</code>, its class file will be obtained from:
245
246<ul><pre>http://www.javassist.org:80/java/org/javassist/test/Main.class
247</pre></ul>
248
249<p>Furthermore, you can directly give a byte array
250to a <code>ClassPool</code> object
251and construct a <code>CtClass</code> object from that array.  To do this,
252use <code>ByteArrayClassPath</code>.  For example,
253
254<ul><pre>
255ClassPool cp = ClassPool.getDefault();
256byte[] b = <em>a byte array</em>;
257String name = <em>class name</em>;
258cp.insertClassPath(new ByteArrayClassPath(name, b));
259CtClass cc = cp.get(name);
260</pre></ul>
261
262<p>The obtained <code>CtClass</code> object represents
263a class defined by the class file specified by <code>b</code>.
264The <code>ClassPool</code> reads a class file from the given
265<code>ByteArrayClassPath</code> if <code>get()</code> is called
266and the class name given to <code>get()</code> is equal to
267one specified by <code>name</code>.
268
269<p>If you do not know the fully-qualified name of the class, then you
270can use <code>makeClass()</code> in <code>ClassPool</code>:
271
272<ul><pre>
273ClassPool cp = ClassPool.getDefault();
274InputStream ins = <em>an input stream for reading a class file</em>;
275CtClass cc = cp.makeClass(ins);
276</pre></ul>
277
278<p><code>makeClass()</code> returns the <code>CtClass</code> object
279constructed from the given input stream.  You can use
280<code>makeClass()</code> for eagerly feeding class files to
281the <code>ClassPool</code> object.  This might improve performance
282if the search path includes a large jar file.  Since
283a <code>ClassPool</code> object reads a class file on demand,
284it might repeatedly search the whole jar file for every class file.
285<code>makeClass()</code> can be used for optimizing this search.
286The <code>CtClass</code> constructed by <code>makeClass()</code>
287is kept in the <code>ClassPool</code> object and the class file is never
288read again.
289
290<p>The users can extend the class search path.  They can define a new
291class implementing <code>ClassPath</code> interface and give an
292instance of that class to <code>insertClassPath()</code> in
293<code>ClassPool</code>.  This allows a non-standard resource to be
294included in the search path.
295
296<p><br>
297
298<a name="pool">
299<h2>2. ClassPool</h2>
300
301<p>
302A <code>ClassPool</code> object is a container of <code>CtClass</code>
303objects.  Once a <code>CtClass</code> object is created, it is
304recorded in a <code>ClassPool</code> for ever.  This is because a
305compiler may need to access the <code>CtClass</code> object later when
306it compiles source code that refers to the class represented by that
307<code>CtClass</code>.
308
309<p>
310For example, suppose that a new method <code>getter()</code> is added
311to a <code>CtClass</code> object representing <code>Point</code>
312class.  Later, the program attempts to compile source code including a
313method call to <code>getter()</code> in <code>Point</code> and use the
314compiled code as the body of a method, which will be added to another
315class <code>Line</code>.  If the <code>CtClass</code> object representing
316<code>Point</code> is lost, the compiler cannot compile the method call
317to <code>getter()</code>.  Note that the original class definition does
318not include <code>getter()</code>.  Therefore, to correctly compile
319such a method call, the <code>ClassPool</code>
320must contain all the instances of <code>CtClass</code> all the time of
321program execution.
322
323<a name="avoidmemory">
324<h4>Avoid out of memory</h4>
325</a>
326
327<p>
328This specification of <code>ClassPool</code> may cause huge memory
329consumption if the number of <code>CtClass</code> objects becomes
330amazingly large (this rarely happens since Javassist tries to reduce
331memory consumption in <a href="#frozenclasses">various ways</a>).
332To avoid this problem, you
333can explicitly remove an unnecessary <code>CtClass</code> object from
334the <code>ClassPool</code>.  If you call <code>detach()</code> on a
335<code>CtClass</code> object, then that <code>CtClass</code> object is
336removed from the <code>ClassPool</code>.  For example,
337
338<ul><pre>
339CtClass cc = ... ;
340cc.writeFile();
341cc.detach();
342</pre></ul>
343
344<p>You must not call any method on that
345<code>CtClass</code> object after <code>detach()</code> is called.
346However, you can call <code>get()</code> on <code>ClassPool</code>
347to make a new instance of <code>CtClass</code> representing
348the same class.  If you call <code>get()</code>, the <code>ClassPool</code>
349reads a class file again and newly creates a <code>CtClass</code>
350object, which is returned by <code>get()</code>.
351
352<p>
353Another idea is to occasionally replace a <code>ClassPool</code> with
354a new one and discard the old one.  If an old <code>ClassPool</code>
355is garbage collected, the <code>CtClass</code> objects included in
356that <code>ClassPool</code> are also garbage collected.
357To create a new instance of <code>ClassPool</code>, execute the following
358code snippet:
359
360<ul><pre>
361ClassPool cp = new ClassPool(true);
362// if needed, append an extra search path by appendClassPath()
363</pre></ul>
364
365<p>This creates a <code>ClassPool</code> object that behaves as the
366default <code>ClassPool</code> returned by
367<code>ClassPool.getDefault()</code> does.
368Note that <code>ClassPool.getDefault()</code> is a singleton factory method
369provided for convenience.  It creates a <code>ClassPool</code> object in
370the same way shown above although it keeps a single instance of
371<code>ClassPool</code> and reuses it.
372A <code>ClassPool</code> object returned by <code>getDefault()</code>
373does not have a special role.  <code>getDefault()</code> is a convenience
374method.
375
376<p>Note that <code>new ClassPool(true)</code> is a convenient constructor,
377which constructs a <code>ClassPool</code> object and appends the system
378search path to it.  Calling that constructor is
379equivalent to the following code:
380
381<ul><pre>
382ClassPool cp = new ClassPool();
383cp.appendSystemPath();  // or append another path by appendClassPath()
384</pre></ul>
385
386<h4>Cascaded ClassPools</h4>
387
388<p>
389<em>If a program is running on a web application server,</em>
390creating multiple instances of <code>ClassPool</code> might be necessary;
391an instance of <code>ClassPool</code> should be created
392for each class loader (i.e. container).
393The program should create a <code>ClassPool</code> object by not calling
394<code>getDefault()</code> but a constructor of <code>ClassPool</code>.
395
396<p>
397Multiple <code>ClassPool</code> objects can be cascaded like
398<code>java.lang.ClassLoader</code>.  For example,
399
400<ul><pre>
401ClassPool parent = ClassPool.getDefault();
402ClassPool child = new ClassPool(parent);
403child.insertClassPath("./classes");
404</pre></ul>
405
406<p>
407If <code>child.get()</code> is called, the child <code>ClassPool</code>
408first delegates to the parent <code>ClassPool</code>.  If the parent
409<code>ClassPool</code> fails to find a class file, then the child
410<code>ClassPool</code> attempts to find a class file
411under the <code>./classes</code> directory.
412
413<p>
414If <code>child.childFirstLookup</code> is true, the child
415<code>ClassPool</code> attempts to find a class file before delegating
416to the parent <code>ClassPool</code>.  For example,
417
418<ul><pre>
419ClassPool parent = ClassPool.getDefault();
420ClassPool child = new ClassPool(parent);
421child.appendSystemPath();         // the same class path as the default one.
422child.childFirstLookup = true;    // changes the behavior of the child.
423</pre></ul>
424
425<h4>Changing a class name for defining a new class</h4>
426
427<p>A new class can be defined as a copy of an existing class.
428The program below does that:
429
430<ul><pre>
431ClassPool pool = ClassPool.getDefault();
432CtClass cc = pool.get("Point");
433cc.setName("Pair");
434</pre></ul>
435
436<p>This program first obtains the <code>CtClass</code> object for
437class <code>Point</code>.  Then it calls <code>setName()</code> to
438give a new name <code>Pair</code> to that <code>CtClass</code> object.
439After this call, all occurrences of the class name in the class
440definition represented by that <code>CtClass</code> object are changed
441from <code>Point</code> to <code>Pair</code>.  The other part of the
442class definition does not change.
443
444<p>Note that <code>setName()</code> in <code>CtClass</code> changes a
445record in the <code>ClassPool</code> object.  From the implementation
446viewpoint, a <code>ClassPool</code> object is a hash table of
447<code>CtClass</code> objects.  <code>setName()</code> changes
448the key associated to the <code>CtClass</code> object in the hash
449table.  The key is changed from the original class name to the new
450class name.
451
452<p>Therefore, if <code>get("Point")</code> is later called on the
453<code>ClassPool</code> object again, then it never returns the
454<code>CtClass</code> object that the variable <code>cc</code> refers to.
455The <code>ClassPool</code> object reads
456a class file
457<code>Point.class</code> again and it constructs a new <code>CtClass</code>
458object for class <code>Point</code>.
459This is because the <code>CtClass</code> object associated with the name
460<code>Point</code> does not exist any more.
461See the followings:
462
463<ul><pre>
464ClassPool pool = ClassPool.getDefault();
465CtClass cc = pool.get("Point");
466CtClass cc1 = pool.get("Point");   // cc1 is identical to cc.
467cc.setName("Pair");
468CtClass cc2 = pool.get("Pair");    // cc2 is identical to cc.
469CtClass cc3 = pool.get("Point");   // cc3 is not identical to cc.
470</pre></ul>
471
472<p><code>cc1</code> and <code>cc2</code> refer to the same instance of
473<code>CtClass</code> that <code>cc</code> does whereas
474<code>cc3</code> does not.  Note that, after
475<code>cc.setName("Pair")</code> is executed, the <code>CtClass</code>
476object that <code>cc</code> and <code>cc1</code> refer to represents
477the <code>Pair</code> class.
478
479<p>The <code>ClassPool</code> object is used to maintain one-to-one
480mapping between classes and <code>CtClass</code> objects.  Javassist
481never allows two distinct <code>CtClass</code> objects to represent
482the same class unless two independent <code>ClassPool</code> are created.
483This is a significant feature for consistent program
484transformation.
485
486<p>To create another copy of the default instance of
487<code>ClassPool</code>, which is returned by
488<code>ClassPool.getDefault()</code>, execute the following code
489snippet (this code was already <a href="#avoidmemory">shown above</a>):
490
491<ul><pre>
492ClassPool cp = new ClassPool(true);
493</pre></ul>
494
495<p>If you have two <code>ClassPool</code> objects, then you can
496obtain, from each <code>ClassPool</code>, a distinct
497<code>CtClass</code> object representing the same class file.  You can
498differently modify these <code>CtClass</code> objects to generate
499different versions of the class.
500
501<h4>Renaming a frozen class for defining a new class</h4>
502
503<p>Once a <code>CtClass</code> object is converted into a class file
504by <code>writeFile()</code> or <code>toBytecode()</code>, Javassist
505rejects further modifications of that <code>CtClass</code> object.
506Hence, after the <code>CtClass</code> object representing <code>Point</code>
507class is converted into a class file, you cannot define <code>Pair</code>
508class as a copy of <code>Point</code> since executing <code>setName()</code>
509on <code>Point</code> is rejected.
510The following code snippet is wrong:
511
512<ul><pre>
513ClassPool pool = ClassPool.getDefault();
514CtClass cc = pool.get("Point");
515cc.writeFile();
516cc.setName("Pair");    // wrong since writeFile() has been called.
517</pre></ul>
518
519<p>To avoid this restriction, you should call <code>getAndRename()</code>
520in <code>ClassPool</code>.  For example,
521
522<ul><pre>
523ClassPool pool = ClassPool.getDefault();
524CtClass cc = pool.get("Point");
525cc.writeFile();
526CtClass cc2 = pool.getAndRename("Point", "Pair");
527</pre></ul>
528
529<p>If <code>getAndRename()</code> is called, the <code>ClassPool</code>
530first reads <code>Point.class</code> for creating a new <code>CtClass</code>
531object representing <code>Point</code> class.  However, it renames that
532<code>CtClass</code> object from <code>Point</code> to <code>Pair</code> before
533it records that <code>CtClass</code> object in a hash table.
534Thus <code>getAndRename()</code>
535can be executed after <code>writeFile()</code> or <code>toBytecode()</code>
536is called on the the <code>CtClass</code> object representing <code>Point</code>
537class.
538
539<p><br>
540
541<a name="load">
542<h2>3. Class loader</h2>
543
544<p>If what classes must be modified is known in advance,
545the easiest way for modifying the classes is as follows:
546
547<ul><li>1. Get a <code>CtClass</code> object by calling
548        <code>ClassPool.get()</code>,
549    <li>2. Modify it, and
550    <li>3. Call <code>writeFile()</code> or <code>toBytecode()</code>
551           on that <code>CtClass</code> object to obtain a modified class file.
552</ul>
553
554<p>If whether a class is modified or not is determined at load time,
555the users must make Javassist collaborate with a class loader.
556Javassist can be used with a class loader so that bytecode can be
557modified at load time.  The users of Javassist can define their own
558version of class loader but they can also use a class loader provided
559by Javassist.
560
561
562<p><br>
563
564<a name="toclass">
565<h3>3.1 The <code>toClass</code> method in <code>CtClass</code></h3>
566</a>
567
568<p>The <code>CtClass</code> provides a convenience method
569<code>toClass()</code>, which requests the context class loader for
570the current thread to load the class represented by the <code>CtClass</code>
571object.  To call this method, the caller must have appropriate permission;
572otherwise, a <code>SecurityException</code> may be thrown.
573
574<p>The following program shows how to use <code>toClass()</code>:
575
576<ul><pre>
577public class Hello {
578    public void say() {
579        System.out.println("Hello");
580    }
581}
582
583public class Test {
584    public static void main(String[] args) throws Exception {
585        ClassPool cp = ClassPool.getDefault();
586        CtClass cc = cp.get("Hello");
587        CtMethod m = cc.getDeclaredMethod("say");
588        m.insertBefore("{ System.out.println(\"Hello.say():\"); }");
589        Class c = cc.toClass();
590        Hello h = (Hello)c.newInstance();
591        h.say();
592    }
593}
594</pre></ul>
595
596<p><code>Test.main()</code> inserts a call to <code>println()</code>
597in the method body of <code>say()</code> in <code>Hello</code>.  Then
598it constructs an instance of the modified <code>Hello</code> class
599and calls <code>say()</code> on that instance.
600
601<p>Note that the program above depends on the fact that the
602<code>Hello</code> class is never loaded before <code>toClass()</code>
603is invoked.  If not, the JVM would load the original
604<code>Hello</code> class before <code>toClass()</code> requests to
605load the modified <code>Hello</code> class.  Hence loading the
606modified <code>Hello</code> class would be failed
607(<code>LinkageError</code> is thrown).  For example, if
608<code>main()</code> in <code>Test</code> is something like this:
609
610<ul><pre>
611public static void main(String[] args) throws Exception {
612    Hello orig = new Hello();
613    ClassPool cp = ClassPool.getDefault();
614    CtClass cc = cp.get("Hello");
615        :
616}
617</pre></ul>
618
619<p>then the original <code>Hello</code> class is loaded at the first
620line of <code>main</code> and the call to <code>toClass()</code>
621throws an exception since the class loader cannot load two different
622versions of the <code>Hello</code> class at the same time.
623
624<p><em>If the program is running on some application server such as
625JBoss and Tomcat,</em> the context class loader used by
626<code>toClass()</code> might be inappropriate.  In this case, you
627would see an unexpected <code>ClassCastException</code>.  To avoid
628this exception, you must explicitly give an appropriate class loader
629to <code>toClass()</code>.  For example, if <code>bean</code> is your
630session bean object, then the following code:
631
632<ul><pre>CtClass cc = ...;
633Class c = cc.toClass(bean.getClass().getClassLoader());
634</pre></ul>
635
636<p>would work.  You should give <code>toClass()</code> the class loader
637that has loaded your program (in the above example, the class of
638the <code>bean</code> object).
639
640<p><code>toClass()</code> is provided for convenience.  If you need
641more complex functionality, you should write your own class loader.
642
643<p><br>
644
645<h3>3.2 Class loading in Java</h3>
646
647<p>In Java, multiple class loaders can coexist and
648each class loader creates its own name space.
649Different class loaders can load different class files with the
650same class name.  The loaded two classes are regarded as different
651ones.  This feature enables us to run multiple application programs
652on a single JVM even if these programs include different classes
653with the same name.
654
655<ul>
656<b>Note:</b> The JVM does not allow dynamically reloading a class.
657Once a class loader loads a class, it cannot reload a modified
658version of that class during runtime.  Thus, you cannot alter
659the definition of a class after the JVM loads it.
660However, the JPDA (Java Platform Debugger Architecture) provides
661limited ability for reloading a class.
662See <a href="#hotswap">Section 3.6</a>.
663</ul>
664
665<p>If the same class file is loaded by two distinct class loaders,
666the JVM makes two distinct classes with the same name and definition.
667The two classes are regarded as different ones.
668Since the two classes are not identical, an instance of one class is
669not assignable to a variable of the other class.  The cast operation
670between the two classes fails
671and throws a <em><code>ClassCastException</code></em>.
672
673<p>For example, the following code snippet throws an exception:
674
675<ul><pre>
676MyClassLoader myLoader = new MyClassLoader();
677Class clazz = myLoader.loadClass("Box");
678Object obj = clazz.newInstance();
679Box b = (Box)obj;    // this always throws ClassCastException.
680</pre></ul>
681
682<p>
683The <code>Box</code> class is loaded by two class loaders.
684Suppose that a class loader CL loads a class including this code snippet.
685Since this code snippet refers to <code>MyClassLoader</code>,
686<code>Class</code>, <code>Object</code>, and <code>Box</code>,
687CL also loads these classes (unless it delegates to another class loader).
688Hence the type of the variable <code>b</code> is the <code>Box</code>
689class loaded by CL.
690On the other hand, <code>myLoader</code> also loads the <code>Box</code>
691class.  The object <code>obj</code> is an instance of
692the <code>Box</code> class loaded by <code>myLoader</code>.
693Therefore, the last statement always throws a
694<code>ClassCastException</code> since the class of <code>obj</code> is
695a different verison of the <code>Box</code> class from one used as the
696type of the variable <code>b</code>.
697
698<p>Multiple class loaders form a tree structure.
699Each class loader except the bootstrap loader has a
700parent class loader, which has normally loaded the class of that child
701class loader.  Since the request to load a class can be delegated along this
702hierarchy of class loaders, a class may be loaded by a class loader that
703you do not request the class loading.
704Therefore, the class loader that has been requested to load a class C
705may be different from the loader that actually loads the class C.
706For distinction, we call the former loader <em>the initiator of C</em>
707and we call the latter loader <em>the real loader of C</em>.
708
709<p>
710Furthermore, if a class loader CL requested to load a class C
711(the initiator of C) delegates
712to the parent class loader PL, then the class loader CL is never requested
713to load any classes referred to in the definition of the class C.
714CL is not the initiator of those classes.
715Instead, the parent class loader PL becomes their initiators
716and it is requested to load them.
717<em>The classes that the definition of a class C referes to are loaded by
718the real loader of C.</em>
719
720<p>To understand this behavior, let's consider the following example.
721
722<ul><pre>
723public class Point {    // loaded by PL
724    private int x, y;
725    public int getX() { return x; }
726        :
727}
728
729public class Box {      // the initiator is L but the real loader is PL
730    private Point upperLeft, size;
731    public int getBaseX() { return upperLeft.x; }
732        :
733}
734
735public class Window {    // loaded by a class loader L
736    private Box box;
737    public int getBaseX() { return box.getBaseX(); }
738}</pre></ul>
739
740<p>Suppose that a class <code>Window</code> is loaded by a class loader L.
741Both the initiator and the real loader of <code>Window</code> are L.
742Since the definition of <code>Window</code> refers to <code>Box</code>,
743the JVM will request L to load <code>Box</code>.
744Here, suppose that L delegates this task to the parent class loader PL.
745The initiator of <code>Box</code> is L but the real loader is PL.
746In this case, the initiator of <code>Point</code> is not L but PL
747since it is the same as the real loader of <code>Box</code>.
748Thus L is never requested to load <code>Point</code>.
749
750<p>Next, let's consider a slightly modified example.
751
752<ul><pre>
753public class Point {
754    private int x, y;
755    public int getX() { return x; }
756        :
757}
758
759public class Box {      // the initiator is L but the real loader is PL
760    private Point upperLeft, size;
761    public Point getSize() { return size; }
762        :
763}
764
765public class Window {    // loaded by a class loader L
766    private Box box;
767    public boolean widthIs(int w) {
768        Point p = box.getSize();
769        return w == p.getX();
770    }
771}</pre></ul>
772
773<p>Now, the definition of <code>Window</code> also refers to
774<code>Point</code>.  In this case, the class loader L must
775also delegate to PL if it is requested to load <code>Point</code>.
776<em>You must avoid having two class loaders doubly load the same
777class.</em>  One of the two loaders must delegate to
778the other.
779
780<p>
781If L does not delegate to PL when <code>Point</code>
782is loaded, <code>widthIs()</code> would throw a ClassCastException.
783Since the real loader of <code>Box</code> is PL,
784<code>Point</code> referred to in <code>Box</code> is also loaded by PL.
785Therefore, the resulting value of <code>getSize()</code>
786is an instance of <code>Point</code> loaded by PL
787whereas the type of the variable <code>p</code> in <code>widthIs()</code>
788is <code>Point</code> loaded by L.
789The JVM regards them as distinct types and thus it throws an exception
790because of type mismatch.
791
792<p>This behavior is somewhat inconvenient but necessary.
793If the following statement:
794
795<ul><pre>
796Point p = box.getSize();
797</pre></ul>
798
799<p>did not throw an exception,
800then the programmer of <code>Window</code> could break the encapsulation
801of <code>Point</code> objects.
802For example, the field <code>x</code>
803is private in <code>Point</code> loaded by PL.
804However, the <code>Window</code> class could
805directly access the value of <code>x</code>
806if L loads <code>Point</code> with the following definition:
807
808<ul><pre>
809public class Point {
810    public int x, y;    // not private
811    public int getX() { return x; }
812        :
813}
814</pre></ul>
815
816<p>
817For more details of class loaders in Java, the following paper would
818be helpful:
819
820<ul>Sheng Liang and Gilad Bracha,
821"Dynamic Class Loading in the Java Virtual Machine",
822<br><i>ACM OOPSLA'98</i>, pp.36-44, 1998.</ul>
823
824<p><br>
825
826<h3>3.3 Using <code>javassist.Loader</code></h3>
827
828<p>Javassist provides a class loader
829<code>javassist.Loader</code>.  This class loader uses a
830<code>javassist.ClassPool</code> object for reading a class file.
831
832<p>For example, <code>javassist.Loader</code> can be used for loading
833a particular class modified with Javassist.
834
835<ul><pre>
836import javassist.*;
837import test.Rectangle;
838
839public class Main {
840  public static void main(String[] args) throws Throwable {
841     ClassPool pool = ClassPool.getDefault();
842     Loader cl = new Loader(pool);
843
844     CtClass ct = pool.get("test.Rectangle");
845     ct.setSuperclass(pool.get("test.Point"));
846
847     Class c = cl.loadClass("test.Rectangle");
848     Object rect = c.newInstance();
849         :
850  }
851}
852</pre></ul>
853
854<p>This program modifies a class <code>test.Rectangle</code>.  The
855superclass of <code>test.Rectangle</code> is set to a
856<code>test.Point</code> class.  Then this program loads the modified
857class, and creates a new instance of the
858<code>test.Rectangle</code> class.
859
860<p>If the users want to modify a class on demand when it is loaded,
861the users can add an event listener to a <code>javassist.Loader</code>.
862The added event listener is
863notified when the class loader loads a class.
864The event-listener class must implement the following interface:
865
866<ul><pre>public interface Translator {
867    public void start(ClassPool pool)
868        throws NotFoundException, CannotCompileException;
869    public void onLoad(ClassPool pool, String classname)
870        throws NotFoundException, CannotCompileException;
871}</pre></ul>
872
873<p>The method <code>start()</code> is called when this event listener
874is added to a <code>javassist.Loader</code> object by
875<code>addTranslator()</code> in <code>javassist.Loader</code>.  The
876method <code>onLoad()</code> is called before
877<code>javassist.Loader</code> loads a class.  <code>onLoad()</code>
878can modify the definition of the loaded class.
879
880<p>For example, the following event listener changes all classes
881to public classes just before they are loaded.
882
883<ul><pre>public class MyTranslator implements Translator {
884    void start(ClassPool pool)
885        throws NotFoundException, CannotCompileException {}
886    void onLoad(ClassPool pool, String classname)
887        throws NotFoundException, CannotCompileException
888    {
889        CtClass cc = pool.get(classname);
890        cc.setModifiers(Modifier.PUBLIC);
891    }
892}</pre></ul>
893
894<p>Note that <code>onLoad()</code> does not have to call
895<code>toBytecode()</code> or <code>writeFile()</code> since
896<code>javassist.Loader</code> calls these methods to obtain a class
897file.
898
899<p>To run an application class <code>MyApp</code> with a
900<code>MyTranslator</code> object, write a main class as following:
901
902<ul><pre>
903import javassist.*;
904
905public class Main2 {
906  public static void main(String[] args) throws Throwable {
907     Translator t = new MyTranslator();
908     ClassPool pool = ClassPool.getDefault();
909     Loader cl = new Loader();
910     cl.addTranslator(pool, t);
911     cl.run("MyApp", args);
912  }
913}
914</pre></ul>
915
916<p>To run this program, do:
917
918<ul><pre>
919% java Main2 <i>arg1</i> <i>arg2</i>...
920</pre></ul>
921
922<p>The class <code>MyApp</code> and the other application classes
923are translated by <code>MyTranslator</code>.
924
925<p>Note that <em>application</em> classes like <code>MyApp</code> cannot
926access the <em>loader</em> classes such as <code>Main2</code>,
927<code>MyTranslator</code>, and <code>ClassPool</code> because they
928are loaded by different loaders.  The application classes are loaded
929by <code>javassist.Loader</code> whereas the loader classes such as
930<code>Main2</code> are by the default Java class loader.
931
932<p><code>javassist.Loader</code> searches for classes in a different
933order from <code>java.lang.ClassLoader</code>.
934<code>ClassLoader</code> first delegates the loading operations to
935the parent class loader and then attempts to load the classes
936only if the parent class loader cannot find them.
937On the other hand,
938<code>javassist.Loader</code> attempts
939to load the classes before delegating to the parent class loader.
940It delegates only if:
941
942<ul><li>the classes are not found by calling <code>get()</code> on
943a <code>ClassPool</code> object, or
944
945<p><li>the classes have been specified by using
946<code>delegateLoadingOf()</code>
947to be loaded by the parent class loader.
948</ul>
949
950<p>This search order allows loading modified classes by Javassist.
951However, it delegates to the parent class loader if it fails
952to find modified classes for some reason.  Once a class is loaded by
953the parent class loader, the other classes referred to in that class will be
954also loaded by the parent class loader and thus they are never modified.
955Recall that all the classes referred to in a class C are loaded by the
956real loader of C.
957<em>If your program fails to load a modified class,</em> you should
958make sure whether all the classes using that class have been loaded by
959<code>javassist.Loader</code>.
960
961<p><br>
962
963<h3>3.4 Writing a class loader</h3>
964
965<p>A simple class loader using Javassist is as follows:
966
967<ul><pre>import javassist.*;
968
969public class SampleLoader extends ClassLoader {
970    /* Call MyApp.main().
971     */
972    public static void main(String[] args) throws Throwable {
973        SampleLoader s = new SampleLoader();
974        Class c = s.loadClass("MyApp");
975        c.getDeclaredMethod("main", new Class[] { String[].class })
976         .invoke(null, new Object[] { args });
977    }
978
979    private ClassPool pool;
980
981    public SampleLoader() throws NotFoundException {
982        pool = new ClassPool();
983        pool.insertClassPath("./class"); // <em>MyApp.class must be there.</em>
984    }
985
986    /* Finds a specified class.
987     * The bytecode for that class can be modified.
988     */
989    protected Class findClass(String name) throws ClassNotFoundException {
990        try {
991            CtClass cc = pool.get(name);
992            // <em>modify the CtClass object here</em>
993            byte[] b = cc.toBytecode();
994            return defineClass(name, b, 0, b.length);
995        } catch (NotFoundException e) {
996            throw new ClassNotFoundException();
997        } catch (IOException e) {
998            throw new ClassNotFoundException();
999        } catch (CannotCompileException e) {
1000            throw new ClassNotFoundException();
1001        }
1002    }
1003}</pre></ul>
1004
1005<p>The class <code>MyApp</code> is an application program.
1006To execute this program, first put the class file under the
1007<code>./class</code> directory, which must <em>not</em> be included
1008in the class search path.  Otherwise, <code>MyApp.class</code> would
1009be loaded by the default system class loader, which is the parent
1010loader of <code>SampleLoader</code>.
1011The directory name <code>./class</code> is specified by
1012<code>insertClassPath()</code> in the constructor.
1013You can choose a different name instead of <code>./class</code> if you want.
1014Then do as follows:
1015
1016<ul><code>% java SampleLoader</code></ul>
1017
1018<p>The class loader loads the class <code>MyApp</code>
1019(<code>./class/MyApp.class</code>) and calls
1020<code>MyApp.main()</code> with the command line parameters.
1021
1022<p>This is the simplest way of using Javassist.  However, if you write
1023a more complex class loader, you may need detailed knowledge of
1024Java's class loading mechanism.  For example, the program above puts the
1025<code>MyApp</code> class in a name space separated from the name space
1026that the class <code>SampleLoader</code> belongs to because the two
1027classes are loaded by different class loaders.
1028Hence, the
1029<code>MyApp</code> class cannot directly access the class
1030<code>SampleLoader</code>.
1031
1032<p><br>
1033
1034<h3>3.5 Modifying a system class</h3>
1035
1036<p>The system classes like <code>java.lang.String</code> cannot be
1037loaded by a class loader other than the system class loader.
1038Therefore, <code>SampleLoader</code> or <code>javassist.Loader</code>
1039shown above cannot modify the system classes at loading time.
1040
1041<p>If your application needs to do that, the system classes must be
1042<em>statically</em> modified.  For example, the following program
1043adds a new field <code>hiddenValue</code> to <code>java.lang.String</code>:
1044
1045<ul><pre>ClassPool pool = ClassPool.getDefault();
1046CtClass cc = pool.get("java.lang.String");
1047cc.addField(new CtField(CtClass.intType, "hiddenValue", cc));
1048cc.writeFile(".");</pre></ul>
1049
1050<p>This program produces a file <code>"./java/lang/String.class"</code>.
1051
1052<p>To run your program <code>MyApp</code>
1053with this modified <code>String</code> class, do as follows:
1054
1055<ul><pre>
1056% java -Xbootclasspath/p:. MyApp <i>arg1</i> <i>arg2</i>...
1057</pre></ul>
1058
1059<p>Suppose that the definition of <code>MyApp</code> is as follows:
1060
1061<ul><pre>public class MyApp {
1062    public static void main(String[] args) throws Exception {
1063        System.out.println(String.class.getField("hiddenValue").getName());
1064    }
1065}</pre></ul>
1066
1067<p>If the modified <code>String</code> class is correctly loaded,
1068<code>MyApp</code> prints <code>hiddenValue</code>.
1069
1070<p><i>Note: Applications that use this technique for the purpose of
1071overriding a system class in <code>rt.jar</code> should not be
1072deployed as doing so would contravene the Java 2 Runtime Environment
1073binary code license.</i>
1074
1075<p><br>
1076
1077<a name="hotswap">
1078<h3>3.6 Reloading a class at runtime</h3></a>
1079
1080<p>If the JVM is launched with the JPDA (Java Platform Debugger
1081Architecture) enabled, a class is dynamically reloadable.  After the
1082JVM loads a class, the old version of the class definition can be
1083unloaded and a new one can be reloaded again.  That is, the definition
1084of that class can be dynamically modified during runtime.  However,
1085the new class definition must be somewhat compatible to the old one.
1086<em>The JVM does not allow schema changes between the two versions.</em>
1087They have the same set of methods and fields.
1088
1089<p>Javassist provides a convenient class for reloading a class at runtime.
1090For more information, see the API documentation of
1091<code>javassist.tools.HotSwapper</code>.
1092
1093<p><br>
1094
1095<a href="tutorial2.html">Next page</a>
1096
1097<hr>
1098Java(TM) is a trademark of Sun Microsystems, Inc.<br>
1099Copyright (C) 2000-2010 by Shigeru Chiba, All rights reserved.
1100</body>
1101</html>
1102