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