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