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"> 11 Getting Started with Javassist 12 </font> 13 14 <p><font size="+2"> 15 Shigeru 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. 37 Java bytecode is stored in a binary file called a class file. 38 Each class file contains one Java class or interface. 39 40 <p>The class <code>Javassist.CtClass</code> is an absatract 41 representation of a class file. A <code>CtClass</code> (compile-time 42 class) object is a handle for dealing with a class file. The 43 following program is a very simple example: 44 45 <ul><pre> 46 ClassPool pool = ClassPool.getDefault(); 47 CtClass cc = pool.get("test.Rectangle"); 48 cc.setSuperclass(pool.get("test.Point")); 49 cc.writeFile(); 50 </pre></ul> 51 52 <p>This program first obtains a <code>ClassPool</code> object, which 53 controls bytecode modification with Javassist. The 54 <code>ClassPool</code> object is a container of <code>CtClass</code> 55 object representing a class file. It reads a class file on demand for 56 constructing a <code>CtClass</code> object and records the 57 constructed object for responding later accesses. 58 59 To modify the definition of a class, the users must first obtain 60 from a <code>ClassPool</code> object 61 a reference to a <code>CtClass</code> object representing that class. 62 <code>get()</code> in <code>ClassPool</code> is used for this purpose. 63 In 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>. 68 The <code>ClassPool</code> object returned by <code>getDfault()</code> 69 searches the default system search path. 70 71 <p>From the implementation viewpoint, <code>ClassPool</code> is a hash 72 table of <code>CtClass</code> objects, which uses the class names as 73 keys. <code>get()</code> in <code>ClassPool</code> searches this hash 74 table to find a <code>CtClass</code> object associated with the 75 specified 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 78 then returned as the resulting value of <code>get()</code>. 79 80 <p>The <code>CtClass</code> object obtained from a <code>ClassPool</code> 81 object can be modified 82 (<a href="tutorial2.html#intro">details of how to modify 83 a <code>CtClass</code></a> will be presented later). 84 In 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 87 class file when <code>writeFile()</code> in <code>CtClass()</code> is 88 finally called. 89 90 <p><code>writeFile()</code> translates the <code>CtClass</code> object 91 into a class file and writes it on a local disk. 92 Javassist also provides a method for directly obtaining the 93 modified bytecode. To obtain the bytecode, call <code>toBytecode()</code>: 94 95 <ul><pre> 96 byte[] b = cc.toBytecode(); 97 </pre></ul> 98 99 <p>You can directly load the <code>CtClass</code> as well: 100 101 <ul><pre> 102 Class clazz = cc.toClass(); 103 </pre></ul> 104 105 <p><code>toClass()</code> requests the context class loader for the current 106 thread to load the class file represented by the <code>CtClass</code>. It 107 returns a <code>java.lang.Class</code> object representing the loaded class. 108 For 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> 114 must be called on a <code>ClassPool</code>. 115 116 <ul><pre> 117 ClassPool pool = ClassPool.getDefault(); 118 CtClass cc = pool.makeClass("Point"); 119 </pre></ul> 120 121 <p>This program defines a class <code>Point</code> 122 including no members. 123 Member methods of <code>Point</code> can be created with 124 factory methods declared in <code>CtNewMethod</code> and 125 appended to <code>Point</code> with <code>addMethod()</code> 126 in <code>CtClass</code>. 127 128 <p><code>makeClass()</code> cannot create a new interface; 129 <code>makeInterface()</code> in <code>ClassPool</code> can do. 130 Member methods in an interface can be created with 131 <code>abstractMethod()</code> in <code>CtNewMethod</code>. 132 Note 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> 140 object. Further modifications of that <code>CtClass</code> object are 141 not permitted. This is for warning the developers when they attempt 142 to modify a class file that has been already loaded since the JVM does 143 not allow reloading a class. 144 145 <p>A frozen <code>CtClass</code> can be defrost so that 146 modifications of the class definition will be permitted. For example, 147 148 <ul><pre> 149 CtClasss cc = ...; 150 : 151 cc.writeFile(); 152 cc.defrost(); 153 cc.setSuperclass(...); // OK since the class is not frozen. 154 </pre></ul> 155 156 <p>After <code>defrost()</code> is called, the <code>CtClass</code> 157 object can be modified again. 158 159 <p>If <code>ClassPool.doPruning</code> is set to <code>true</code>, 160 then Javassist prunes the data structure contained 161 in a <code>CtClass</code> object 162 when Javassist freezes that object. 163 To reduce memory 164 consumption, pruning discards unnecessary attributes 165 (<code>attribute_info</code> structures) in that object. 166 For example, <code>Code_attribute</code> structures (method bodies) 167 are discarded. 168 Thus, after a 169 <code>CtClass</code> object is pruned, the bytecode of a method is not 170 accessible except method names, signatures, and annotations. 171 The pruned <code>CtClass</code> object cannot be defrost again. 172 The 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> 178 CtClasss cc = ...; 179 cc.stopPruning(true); 180 : 181 cc.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. 186 Thus it can be defrost after <code>writeFile()</code> is called. 187 188 <ul><b>Note:</b> 189 While debugging, you might want to temporarily stop pruning and freezing 190 and write a modified class file to a disk drive. 191 <code>debugWriteFile()</code> is a convenient method 192 for that purpose. It stops pruning, writes a class file, defrosts it, 193 and 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 201 by a static method <code>ClassPool.getDefault()</code> 202 searches 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, 204 the <code>ClassPool</code> object may not be able to find user classes</em> 205 since such a web application server uses multiple class loaders as well as 206 the system class loader. In that case, an additional class path must be 207 registered to the <code>ClassPool</code>. Suppose that <code>pool</code> 208 refers to a <code>ClassPool</code> object: 209 210 <ul><pre> 211 pool.insertClassPath(new ClassClassPath(this.getClass())); 212 </pre></ul> 213 214 <p> 215 This statement registers the class path that was used for loading 216 the class of the object that <code>this</code> refers to. 217 You can use any <code>Class</code> object as an argument instead of 218 <code>this.getClass()</code>. The class path used for loading the 219 class represented by that <code>Class</code> object is registered. 220 221 <p> 222 You can register a directory name as the class search path. 223 For example, the following code adds a directory 224 <code>/usr/local/javalib</code> 225 to the search path: 226 227 <ul><pre> 228 ClassPool pool = ClassPool.getDefault(); 229 pool.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 233 a URL: 234 235 <ul><pre> 236 ClassPool pool = ClassPool.getDefault(); 237 ClassPath cp = new URLClassPath("www.javassist.org", 80, "/java/", "org.javassist."); 238 pool.insertClassPath(cp); 239 </pre></ul> 240 241 <p>This program adds "http://www.javassist.org:80/java/" to the class search 242 path. This URL is used only for searching classes belonging to a 243 package <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 250 to a <code>ClassPool</code> object 251 and construct a <code>CtClass</code> object from that array. To do this, 252 use <code>ByteArrayClassPath</code>. For example, 253 254 <ul><pre> 255 ClassPool cp = ClassPool.getDefault(); 256 byte[] b = <em>a byte array</em>; 257 String name = <em>class name</em>; 258 cp.insertClassPath(new ByteArrayClassPath(name, b)); 259 CtClass cc = cp.get(name); 260 </pre></ul> 261 262 <p>The obtained <code>CtClass</code> object represents 263 a class defined by the class file specified by <code>b</code>. 264 The <code>ClassPool</code> reads a class file from the given 265 <code>ByteArrayClassPath</code> if <code>get()</code> is called 266 and the class name given to <code>get()</code> is equal to 267 one specified by <code>name</code>. 268 269 <p>If you do not know the fully-qualified name of the class, then you 270 can use <code>makeClass()</code> in <code>ClassPool</code>: 271 272 <ul><pre> 273 ClassPool cp = ClassPool.getDefault(); 274 InputStream ins = <em>an input stream for reading a class file</em>; 275 CtClass cc = cp.makeClass(ins); 276 </pre></ul> 277 278 <p><code>makeClass()</code> returns the <code>CtClass</code> object 279 constructed from the given input stream. You can use 280 <code>makeClass()</code> for eagerly feeding class files to 281 the <code>ClassPool</code> object. This might improve performance 282 if the search path includes a large jar file. Since 283 a <code>ClassPool</code> object reads a class file on demand, 284 it might repeatedly search the whole jar file for every class file. 285 <code>makeClass()</code> can be used for optimizing this search. 286 The <code>CtClass</code> constructed by <code>makeClass()</code> 287 is kept in the <code>ClassPool</code> object and the class file is never 288 read again. 289 290 <p>The users can extend the class search path. They can define a new 291 class implementing <code>ClassPath</code> interface and give an 292 instance of that class to <code>insertClassPath()</code> in 293 <code>ClassPool</code>. This allows a non-standard resource to be 294 included in the search path. 295 296 <p><br> 297 298 <a name="pool"> 299 <h2>2. ClassPool</h2> 300 301 <p> 302 A <code>ClassPool</code> object is a container of <code>CtClass</code> 303 objects. Once a <code>CtClass</code> object is created, it is 304 recorded in a <code>ClassPool</code> for ever. This is because a 305 compiler may need to access the <code>CtClass</code> object later when 306 it compiles source code that refers to the class represented by that 307 <code>CtClass</code>. 308 309 <p> 310 For example, suppose that a new method <code>getter()</code> is added 311 to a <code>CtClass</code> object representing <code>Point</code> 312 class. Later, the program attempts to compile source code including a 313 method call to <code>getter()</code> in <code>Point</code> and use the 314 compiled code as the body of a method, which will be added to another 315 class <code>Line</code>. If the <code>CtClass</code> object representing 316 <code>Point</code> is lost, the compiler cannot compile the method call 317 to <code>getter()</code>. Note that the original class definition does 318 not include <code>getter()</code>. Therefore, to correctly compile 319 such a method call, the <code>ClassPool</code> 320 must contain all the instances of <code>CtClass</code> all the time of 321 program execution. 322 323 <a name="avoidmemory"> 324 <h4>Avoid out of memory</h4> 325 </a> 326 327 <p> 328 This specification of <code>ClassPool</code> may cause huge memory 329 consumption if the number of <code>CtClass</code> objects becomes 330 amazingly large (this rarely happens since Javassist tries to reduce 331 memory consumption in <a href="#frozenclasses">various ways</a>). 332 To avoid this problem, you 333 can explicitly remove an unnecessary <code>CtClass</code> object from 334 the <code>ClassPool</code>. If you call <code>detach()</code> on a 335 <code>CtClass</code> object, then that <code>CtClass</code> object is 336 removed from the <code>ClassPool</code>. For example, 337 338 <ul><pre> 339 CtClass cc = ... ; 340 cc.writeFile(); 341 cc.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. 346 However, you can call <code>get()</code> on <code>ClassPool</code> 347 to make a new instance of <code>CtClass</code> representing 348 the same class. If you call <code>get()</code>, the <code>ClassPool</code> 349 reads a class file again and newly creates a <code>CtClass</code> 350 object, which is returned by <code>get()</code>. 351 352 <p> 353 Another idea is to occasionally replace a <code>ClassPool</code> with 354 a new one and discard the old one. If an old <code>ClassPool</code> 355 is garbage collected, the <code>CtClass</code> objects included in 356 that <code>ClassPool</code> are also garbage collected. 357 To create a new instance of <code>ClassPool</code>, execute the following 358 code snippet: 359 360 <ul><pre> 361 ClassPool 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 366 default <code>ClassPool</code> returned by 367 <code>ClassPool.getDefault()</code> does. 368 Note that <code>ClassPool.getDefault()</code> is a singleton factory method 369 provided for convenience. It creates a <code>ClassPool</code> object in 370 the same way shown above although it keeps a single instance of 371 <code>ClassPool</code> and reuses it. 372 A <code>ClassPool</code> object returned by <code>getDefault()</code> 373 does not have a special role. <code>getDefault()</code> is a convenience 374 method. 375 376 <p>Note that <code>new ClassPool(true)</code> is a convenient constructor, 377 which constructs a <code>ClassPool</code> object and appends the system 378 search path to it. Calling that constructor is 379 equivalent to the following code: 380 381 <ul><pre> 382 ClassPool cp = new ClassPool(); 383 cp.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> 390 creating multiple instances of <code>ClassPool</code> might be necessary; 391 an instance of <code>ClassPool</code> should be created 392 for each class loader (i.e. container). 393 The 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> 397 Multiple <code>ClassPool</code> objects can be cascaded like 398 <code>java.lang.ClassLoader</code>. For example, 399 400 <ul><pre> 401 ClassPool parent = ClassPool.getDefault(); 402 ClassPool child = new ClassPool(parent); 403 child.insertClassPath("./classes"); 404 </pre></ul> 405 406 <p> 407 If <code>child.get()</code> is called, the child <code>ClassPool</code> 408 first 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 411 under the <code>./classes</code> directory. 412 413 <p> 414 If <code>child.childFirstLookup</code> is true, the child 415 <code>ClassPool</code> attempts to find a class file before delegating 416 to the parent <code>ClassPool</code>. For example, 417 418 <ul><pre> 419 ClassPool parent = ClassPool.getDefault(); 420 ClassPool child = new ClassPool(parent); 421 child.appendSystemPath(); // the same class path as the default one. 422 child.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. 428 The program below does that: 429 430 <ul><pre> 431 ClassPool pool = ClassPool.getDefault(); 432 CtClass cc = pool.get("Point"); 433 cc.setName("Pair"); 434 </pre></ul> 435 436 <p>This program first obtains the <code>CtClass</code> object for 437 class <code>Point</code>. Then it calls <code>setName()</code> to 438 give a new name <code>Pair</code> to that <code>CtClass</code> object. 439 After this call, all occurrences of the class name in the class 440 definition represented by that <code>CtClass</code> object are changed 441 from <code>Point</code> to <code>Pair</code>. The other part of the 442 class definition does not change. 443 444 <p>Note that <code>setName()</code> in <code>CtClass</code> changes a 445 record in the <code>ClassPool</code> object. From the implementation 446 viewpoint, a <code>ClassPool</code> object is a hash table of 447 <code>CtClass</code> objects. <code>setName()</code> changes 448 the key associated to the <code>CtClass</code> object in the hash 449 table. The key is changed from the original class name to the new 450 class 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. 455 The <code>ClassPool</code> object reads 456 a class file 457 <code>Point.class</code> again and it constructs a new <code>CtClass</code> 458 object for class <code>Point</code>. 459 This is because the <code>CtClass</code> object associated with the name 460 <code>Point</code> does not exist any more. 461 See the followings: 462 463 <ul><pre> 464 ClassPool pool = ClassPool.getDefault(); 465 CtClass cc = pool.get("Point"); 466 CtClass cc1 = pool.get("Point"); // cc1 is identical to cc. 467 cc.setName("Pair"); 468 CtClass cc2 = pool.get("Pair"); // cc2 is identical to cc. 469 CtClass 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> 476 object that <code>cc</code> and <code>cc1</code> refer to represents 477 the <code>Pair</code> class. 478 479 <p>The <code>ClassPool</code> object is used to maintain one-to-one 480 mapping between classes and <code>CtClass</code> objects. Javassist 481 never allows two distinct <code>CtClass</code> objects to represent 482 the same class unless two independent <code>ClassPool</code> are created. 483 This is a significant feature for consistent program 484 transformation. 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 489 snippet (this code was already <a href="#avoidmemory">shown above</a>): 490 491 <ul><pre> 492 ClassPool cp = new ClassPool(true); 493 </pre></ul> 494 495 <p>If you have two <code>ClassPool</code> objects, then you can 496 obtain, from each <code>ClassPool</code>, a distinct 497 <code>CtClass</code> object representing the same class file. You can 498 differently modify these <code>CtClass</code> objects to generate 499 different 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 504 by <code>writeFile()</code> or <code>toBytecode()</code>, Javassist 505 rejects further modifications of that <code>CtClass</code> object. 506 Hence, after the <code>CtClass</code> object representing <code>Point</code> 507 class is converted into a class file, you cannot define <code>Pair</code> 508 class as a copy of <code>Point</code> since executing <code>setName()</code> 509 on <code>Point</code> is rejected. 510 The following code snippet is wrong: 511 512 <ul><pre> 513 ClassPool pool = ClassPool.getDefault(); 514 CtClass cc = pool.get("Point"); 515 cc.writeFile(); 516 cc.setName("Pair"); // wrong since writeFile() has been called. 517 </pre></ul> 518 519 <p>To avoid this restriction, you should call <code>getAndRename()</code> 520 in <code>ClassPool</code>. For example, 521 522 <ul><pre> 523 ClassPool pool = ClassPool.getDefault(); 524 CtClass cc = pool.get("Point"); 525 cc.writeFile(); 526 CtClass cc2 = pool.getAndRename("Point", "Pair"); 527 </pre></ul> 528 529 <p>If <code>getAndRename()</code> is called, the <code>ClassPool</code> 530 first reads <code>Point.class</code> for creating a new <code>CtClass</code> 531 object representing <code>Point</code> class. However, it renames that 532 <code>CtClass</code> object from <code>Point</code> to <code>Pair</code> before 533 it records that <code>CtClass</code> object in a hash table. 534 Thus <code>getAndRename()</code> 535 can be executed after <code>writeFile()</code> or <code>toBytecode()</code> 536 is called on the the <code>CtClass</code> object representing <code>Point</code> 537 class. 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, 545 the 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, 555 the users must make Javassist collaborate with a class loader. 556 Javassist can be used with a class loader so that bytecode can be 557 modified at load time. The users of Javassist can define their own 558 version of class loader but they can also use a class loader provided 559 by 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 570 the current thread to load the class represented by the <code>CtClass</code> 571 object. To call this method, the caller must have appropriate permission; 572 otherwise, a <code>SecurityException</code> may be thrown. 573 574 <p>The following program shows how to use <code>toClass()</code>: 575 576 <ul><pre> 577 public class Hello { 578 public void say() { 579 System.out.println("Hello"); 580 } 581 } 582 583 public 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> 597 in the method body of <code>say()</code> in <code>Hello</code>. Then 598 it constructs an instance of the modified <code>Hello</code> class 599 and 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> 603 is invoked. If not, the JVM would load the original 604 <code>Hello</code> class before <code>toClass()</code> requests to 605 load the modified <code>Hello</code> class. Hence loading the 606 modified <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> 611 public 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 620 line of <code>main</code> and the call to <code>toClass()</code> 621 throws an exception since the class loader cannot load two different 622 versions 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 625 JBoss and Tomcat,</em> the context class loader used by 626 <code>toClass()</code> might be inappropriate. In this case, you 627 would see an unexpected <code>ClassCastException</code>. To avoid 628 this exception, you must explicitly give an appropriate class loader 629 to <code>toClass()</code>. For example, if <code>bean</code> is your 630 session bean object, then the following code: 631 632 <ul><pre>CtClass cc = ...; 633 Class c = cc.toClass(bean.getClass().getClassLoader()); 634 </pre></ul> 635 636 <p>would work. You should give <code>toClass()</code> the class loader 637 that has loaded your program (in the above example, the class of 638 the <code>bean</code> object). 639 640 <p><code>toClass()</code> is provided for convenience. If you need 641 more 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 648 each class loader creates its own name space. 649 Different class loaders can load different class files with the 650 same class name. The loaded two classes are regarded as different 651 ones. This feature enables us to run multiple application programs 652 on a single JVM even if these programs include different classes 653 with the same name. 654 655 <ul> 656 <b>Note:</b> The JVM does not allow dynamically reloading a class. 657 Once a class loader loads a class, it cannot reload a modified 658 version of that class during runtime. Thus, you cannot alter 659 the definition of a class after the JVM loads it. 660 However, the JPDA (Java Platform Debugger Architecture) provides 661 limited ability for reloading a class. 662 See <a href="#hotswap">Section 3.6</a>. 663 </ul> 664 665 <p>If the same class file is loaded by two distinct class loaders, 666 the JVM makes two distinct classes with the same name and definition. 667 The two classes are regarded as different ones. 668 Since the two classes are not identical, an instance of one class is 669 not assignable to a variable of the other class. The cast operation 670 between the two classes fails 671 and throws a <em><code>ClassCastException</code></em>. 672 673 <p>For example, the following code snippet throws an exception: 674 675 <ul><pre> 676 MyClassLoader myLoader = new MyClassLoader(); 677 Class clazz = myLoader.loadClass("Box"); 678 Object obj = clazz.newInstance(); 679 Box b = (Box)obj; // this always throws ClassCastException. 680 </pre></ul> 681 682 <p> 683 The <code>Box</code> class is loaded by two class loaders. 684 Suppose that a class loader CL loads a class including this code snippet. 685 Since this code snippet refers to <code>MyClassLoader</code>, 686 <code>Class</code>, <code>Object</code>, and <code>Box</code>, 687 CL also loads these classes (unless it delegates to another class loader). 688 Hence the type of the variable <code>b</code> is the <code>Box</code> 689 class loaded by CL. 690 On the other hand, <code>myLoader</code> also loads the <code>Box</code> 691 class. The object <code>obj</code> is an instance of 692 the <code>Box</code> class loaded by <code>myLoader</code>. 693 Therefore, the last statement always throws a 694 <code>ClassCastException</code> since the class of <code>obj</code> is 695 a different verison of the <code>Box</code> class from one used as the 696 type of the variable <code>b</code>. 697 698 <p>Multiple class loaders form a tree structure. 699 Each class loader except the bootstrap loader has a 700 parent class loader, which has normally loaded the class of that child 701 class loader. Since the request to load a class can be delegated along this 702 hierarchy of class loaders, a class may be loaded by a class loader that 703 you do not request the class loading. 704 Therefore, the class loader that has been requested to load a class C 705 may be different from the loader that actually loads the class C. 706 For distinction, we call the former loader <em>the initiator of C</em> 707 and we call the latter loader <em>the real loader of C</em>. 708 709 <p> 710 Furthermore, if a class loader CL requested to load a class C 711 (the initiator of C) delegates 712 to the parent class loader PL, then the class loader CL is never requested 713 to load any classes referred to in the definition of the class C. 714 CL is not the initiator of those classes. 715 Instead, the parent class loader PL becomes their initiators 716 and it is requested to load them. 717 <em>The classes that the definition of a class C referes to are loaded by 718 the real loader of C.</em> 719 720 <p>To understand this behavior, let's consider the following example. 721 722 <ul><pre> 723 public class Point { // loaded by PL 724 private int x, y; 725 public int getX() { return x; } 726 : 727 } 728 729 public 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 735 public 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. 741 Both the initiator and the real loader of <code>Window</code> are L. 742 Since the definition of <code>Window</code> refers to <code>Box</code>, 743 the JVM will request L to load <code>Box</code>. 744 Here, suppose that L delegates this task to the parent class loader PL. 745 The initiator of <code>Box</code> is L but the real loader is PL. 746 In this case, the initiator of <code>Point</code> is not L but PL 747 since it is the same as the real loader of <code>Box</code>. 748 Thus L is never requested to load <code>Point</code>. 749 750 <p>Next, let's consider a slightly modified example. 751 752 <ul><pre> 753 public class Point { 754 private int x, y; 755 public int getX() { return x; } 756 : 757 } 758 759 public 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 765 public 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 775 also 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 777 class.</em> One of the two loaders must delegate to 778 the other. 779 780 <p> 781 If L does not delegate to PL when <code>Point</code> 782 is loaded, <code>widthIs()</code> would throw a ClassCastException. 783 Since the real loader of <code>Box</code> is PL, 784 <code>Point</code> referred to in <code>Box</code> is also loaded by PL. 785 Therefore, the resulting value of <code>getSize()</code> 786 is an instance of <code>Point</code> loaded by PL 787 whereas the type of the variable <code>p</code> in <code>widthIs()</code> 788 is <code>Point</code> loaded by L. 789 The JVM regards them as distinct types and thus it throws an exception 790 because of type mismatch. 791 792 <p>This behavior is somewhat inconvenient but necessary. 793 If the following statement: 794 795 <ul><pre> 796 Point p = box.getSize(); 797 </pre></ul> 798 799 <p>did not throw an exception, 800 then the programmer of <code>Window</code> could break the encapsulation 801 of <code>Point</code> objects. 802 For example, the field <code>x</code> 803 is private in <code>Point</code> loaded by PL. 804 However, the <code>Window</code> class could 805 directly access the value of <code>x</code> 806 if L loads <code>Point</code> with the following definition: 807 808 <ul><pre> 809 public class Point { 810 public int x, y; // not private 811 public int getX() { return x; } 812 : 813 } 814 </pre></ul> 815 816 <p> 817 For more details of class loaders in Java, the following paper would 818 be 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 833 a particular class modified with Javassist. 834 835 <ul><pre> 836 import javassist.*; 837 import test.Rectangle; 838 839 public 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 855 superclass of <code>test.Rectangle</code> is set to a 856 <code>test.Point</code> class. Then this program loads the modified 857 class, 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, 861 the users can add an event listener to a <code>javassist.Loader</code>. 862 The added event listener is 863 notified when the class loader loads a class. 864 The 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 874 is added to a <code>javassist.Loader</code> object by 875 <code>addTranslator()</code> in <code>javassist.Loader</code>. The 876 method <code>onLoad()</code> is called before 877 <code>javassist.Loader</code> loads a class. <code>onLoad()</code> 878 can modify the definition of the loaded class. 879 880 <p>For example, the following event listener changes all classes 881 to 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 897 file. 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> 903 import javassist.*; 904 905 public 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 923 are translated by <code>MyTranslator</code>. 924 925 <p>Note that <em>application</em> classes like <code>MyApp</code> cannot 926 access the <em>loader</em> classes such as <code>Main2</code>, 927 <code>MyTranslator</code>, and <code>ClassPool</code> because they 928 are loaded by different loaders. The application classes are loaded 929 by <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 933 order from <code>java.lang.ClassLoader</code>. 934 <code>ClassLoader</code> first delegates the loading operations to 935 the parent class loader and then attempts to load the classes 936 only if the parent class loader cannot find them. 937 On the other hand, 938 <code>javassist.Loader</code> attempts 939 to load the classes before delegating to the parent class loader. 940 It delegates only if: 941 942 <ul><li>the classes are not found by calling <code>get()</code> on 943 a <code>ClassPool</code> object, or 944 945 <p><li>the classes have been specified by using 946 <code>delegateLoadingOf()</code> 947 to be loaded by the parent class loader. 948 </ul> 949 950 <p>This search order allows loading modified classes by Javassist. 951 However, it delegates to the parent class loader if it fails 952 to find modified classes for some reason. Once a class is loaded by 953 the parent class loader, the other classes referred to in that class will be 954 also loaded by the parent class loader and thus they are never modified. 955 Recall that all the classes referred to in a class C are loaded by the 956 real loader of C. 957 <em>If your program fails to load a modified class,</em> you should 958 make 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 969 public 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. 1006 To execute this program, first put the class file under the 1007 <code>./class</code> directory, which must <em>not</em> be included 1008 in the class search path. Otherwise, <code>MyApp.class</code> would 1009 be loaded by the default system class loader, which is the parent 1010 loader of <code>SampleLoader</code>. 1011 The directory name <code>./class</code> is specified by 1012 <code>insertClassPath()</code> in the constructor. 1013 You can choose a different name instead of <code>./class</code> if you want. 1014 Then 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 1023 a more complex class loader, you may need detailed knowledge of 1024 Java'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 1026 that the class <code>SampleLoader</code> belongs to because the two 1027 classes are loaded by different class loaders. 1028 Hence, 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 1037 loaded by a class loader other than the system class loader. 1038 Therefore, <code>SampleLoader</code> or <code>javassist.Loader</code> 1039 shown 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 1043 adds a new field <code>hiddenValue</code> to <code>java.lang.String</code>: 1044 1045 <ul><pre>ClassPool pool = ClassPool.getDefault(); 1046 CtClass cc = pool.get("java.lang.String"); 1047 cc.addField(new CtField(CtClass.intType, "hiddenValue", cc)); 1048 cc.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> 1053 with 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 1071 overriding a system class in <code>rt.jar</code> should not be 1072 deployed as doing so would contravene the Java 2 Runtime Environment 1073 binary 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 1081 Architecture) enabled, a class is dynamically reloadable. After the 1082 JVM loads a class, the old version of the class definition can be 1083 unloaded and a new one can be reloaded again. That is, the definition 1084 of that class can be dynamically modified during runtime. However, 1085 the 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> 1087 They have the same set of methods and fields. 1088 1089 <p>Javassist provides a convenient class for reloading a class at runtime. 1090 For 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> 1098 Java(TM) is a trademark of Sun Microsystems, Inc.<br> 1099 Copyright (C) 2000-2010 by Shigeru Chiba, All rights reserved. 1100 </body> 1101 </html> 1102