Home | History | Annotate | Download | only in tutorial
      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