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