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