1106 lines
		
	
	
		
			41 KiB
		
	
	
	
		
			HTML
		
	
	
	
			
		
		
	
	
			1106 lines
		
	
	
		
			41 KiB
		
	
	
	
		
			HTML
		
	
	
	
<html>
 | 
						|
<head>
 | 
						|
   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
 | 
						|
   <title>Javassist Tutorial</title>
 | 
						|
   <link rel="stylesheet" type="text/css" href="brown.css">
 | 
						|
</head>
 | 
						|
<body>
 | 
						|
 | 
						|
<b>
 | 
						|
<font size="+3">
 | 
						|
Getting Started with Javassist
 | 
						|
</font>
 | 
						|
 | 
						|
<p><font size="+2">
 | 
						|
Shigeru Chiba
 | 
						|
</font>
 | 
						|
</b>
 | 
						|
 | 
						|
<p><div align="right"><a href="tutorial2.html">Next page</a></div>
 | 
						|
 | 
						|
<ul>1. <a href="#read">Reading and writing bytecode</a>
 | 
						|
<br>2. <a href="#pool">ClassPool</a>
 | 
						|
<br>3. <a href="#load">Class loader</a>
 | 
						|
<br>4. <a href="tutorial2.html#intro">Introspection and customization</a>
 | 
						|
<br>5. <a href="tutorial3.html#intro">Bytecode level API</a>
 | 
						|
<br>6. <a href="tutorial3.html#generics">Generics</a>
 | 
						|
<br>7. <a href="tutorial3.html#varargs">Varargs</a>
 | 
						|
<br>8. <a href="tutorial3.html#j2me">J2ME</a>
 | 
						|
<br>9. <a href="tutorial3.html#boxing">Boxing/Unboxing</a>
 | 
						|
<br>10. <a href="tutorial3.html#debug">Debug</a>
 | 
						|
</ul>
 | 
						|
 | 
						|
<p><br>
 | 
						|
 | 
						|
<a name="read">
 | 
						|
<h2>1. Reading and writing bytecode</h2>
 | 
						|
 | 
						|
<p>Javassist is a class library for dealing with Java bytecode.
 | 
						|
Java bytecode is stored in a binary file called a class file.
 | 
						|
Each class file contains one Java class or interface.
 | 
						|
 | 
						|
<p>The class <code>Javassist.CtClass</code> is an abstract
 | 
						|
representation of a class file.  A <code>CtClass</code> (compile-time
 | 
						|
class) object is a handle for dealing with a class file.  The
 | 
						|
following program is a very simple example:
 | 
						|
 | 
						|
<ul><pre>
 | 
						|
ClassPool pool = ClassPool.getDefault();
 | 
						|
CtClass cc = pool.get("test.Rectangle");
 | 
						|
cc.setSuperclass(pool.get("test.Point"));
 | 
						|
cc.writeFile();
 | 
						|
</pre></ul>
 | 
						|
 | 
						|
<p>This program first obtains a <code>ClassPool</code> object, which
 | 
						|
controls bytecode modification with Javassist.  The
 | 
						|
<code>ClassPool</code> object is a container of <code>CtClass</code>
 | 
						|
object representing a class file.  It reads a class file on demand for
 | 
						|
constructing a <code>CtClass</code> object and records the
 | 
						|
constructed object for responding later accesses.
 | 
						|
 | 
						|
To modify the definition of a class, the users must first obtain
 | 
						|
from a <code>ClassPool</code> object
 | 
						|
a reference to a <code>CtClass</code> object representing that class.
 | 
						|
<code>get()</code> in <code>ClassPool</code> is used for this purpose.
 | 
						|
In the case of the program shown above, the
 | 
						|
<code>CtClass</code> object representing a class
 | 
						|
<code>test.Rectangle</code> is obtained from the
 | 
						|
<code>ClassPool</code> object and it is assigned to a variable
 | 
						|
<code>cc</code>.
 | 
						|
The <code>ClassPool</code> object returned by <code>getDefault()</code>
 | 
						|
searches the default system search path.
 | 
						|
 | 
						|
<p>From the implementation viewpoint, <code>ClassPool</code> is a hash
 | 
						|
table of <code>CtClass</code> objects, which uses the class names as
 | 
						|
keys.  <code>get()</code> in <code>ClassPool</code> searches this hash
 | 
						|
table to find a <code>CtClass</code> object associated with the
 | 
						|
specified key.  If such a <code>CtClass</code> object is not found,
 | 
						|
<code>get()</code> reads a class file to construct a new
 | 
						|
<code>CtClass</code> object, which is recorded in the hash table and
 | 
						|
then returned as the resulting value of <code>get()</code>.
 | 
						|
 | 
						|
<p>The <code>CtClass</code> object obtained from a <code>ClassPool</code>
 | 
						|
object can be modified
 | 
						|
(<a href="tutorial2.html#intro">details of how to modify
 | 
						|
a <code>CtClass</code></a> will be presented later).
 | 
						|
In the example above, it is modified so that the superclass of
 | 
						|
<code>test.Rectangle</code> is changed into a class
 | 
						|
<code>test.Point</code>.  This change is reflected on the original
 | 
						|
class file when <code>writeFile()</code> in <code>CtClass()</code> is
 | 
						|
finally called.
 | 
						|
 | 
						|
<p><code>writeFile()</code> translates the <code>CtClass</code> object
 | 
						|
into a class file and writes it on a local disk.
 | 
						|
Javassist also provides a method for directly obtaining the
 | 
						|
modified bytecode.  To obtain the bytecode, call <code>toBytecode()</code>:
 | 
						|
 | 
						|
<ul><pre>
 | 
						|
byte[] b = cc.toBytecode();
 | 
						|
</pre></ul>
 | 
						|
 | 
						|
<p>You can directly load the <code>CtClass</code> as well:
 | 
						|
 | 
						|
<ul><pre>
 | 
						|
Class clazz = cc.toClass();
 | 
						|
</pre></ul>
 | 
						|
 | 
						|
<p><code>toClass()</code> requests the context class loader for the current
 | 
						|
thread to load the class file represented by the <code>CtClass</code>.  It
 | 
						|
returns a <code>java.lang.Class</code> object representing the loaded class.
 | 
						|
For more details, please see <a href="#toclass">this section below</a>.
 | 
						|
 | 
						|
<a name="def">
 | 
						|
<h4>Defining a new class</h4>
 | 
						|
 | 
						|
<p>To define a new class from scratch, <code>makeClass()</code>
 | 
						|
must be called on a <code>ClassPool</code>.
 | 
						|
 | 
						|
<ul><pre>
 | 
						|
ClassPool pool = ClassPool.getDefault();
 | 
						|
CtClass cc = pool.makeClass("Point");
 | 
						|
</pre></ul>
 | 
						|
 | 
						|
<p>This program defines a class <code>Point</code>
 | 
						|
including no members.
 | 
						|
Member methods of <code>Point</code> can be created with
 | 
						|
factory methods declared in <code>CtNewMethod</code> and
 | 
						|
appended to <code>Point</code> with <code>addMethod()</code>
 | 
						|
in <code>CtClass</code>.
 | 
						|
 | 
						|
<p><code>makeClass()</code> cannot create a new interface;
 | 
						|
<code>makeInterface()</code> in <code>ClassPool</code> can do.
 | 
						|
Member methods in an interface can be created with
 | 
						|
<code>abstractMethod()</code> in <code>CtNewMethod</code>.
 | 
						|
Note that an interface method is an abstract method.
 | 
						|
 | 
						|
<a name="frozenclasses">
 | 
						|
<h4>Frozen classes</h4></a>
 | 
						|
 | 
						|
<p>If a <code>CtClass</code> object is converted into a class file by
 | 
						|
<code>writeFile()</code>, <code>toClass()</code>, or
 | 
						|
<code>toBytecode()</code>, Javassist freezes that <code>CtClass</code>
 | 
						|
object.  Further modifications of that <code>CtClass</code> object are
 | 
						|
not permitted.  This is for warning the developers when they attempt
 | 
						|
to modify a class file that has been already loaded since the JVM does
 | 
						|
not allow reloading a class.
 | 
						|
 | 
						|
<p>A frozen <code>CtClass</code> can be defrost so that
 | 
						|
modifications of the class definition will be permitted.  For example,
 | 
						|
 | 
						|
<ul><pre>
 | 
						|
CtClasss cc = ...;
 | 
						|
    :
 | 
						|
cc.writeFile();
 | 
						|
cc.defrost();
 | 
						|
cc.setSuperclass(...);    // OK since the class is not frozen.
 | 
						|
</pre></ul>
 | 
						|
 | 
						|
<p>After <code>defrost()</code> is called, the <code>CtClass</code>
 | 
						|
object can be modified again.
 | 
						|
 | 
						|
<p>If <code>ClassPool.doPruning</code> is set to <code>true</code>,
 | 
						|
then Javassist prunes the data structure contained
 | 
						|
in a <code>CtClass</code> object
 | 
						|
when Javassist freezes that object.
 | 
						|
To reduce memory
 | 
						|
consumption, pruning discards unnecessary attributes
 | 
						|
(<code>attribute_info</code> structures) in that object.
 | 
						|
For example, <code>Code_attribute</code> structures (method bodies)
 | 
						|
are discarded.
 | 
						|
Thus, after a
 | 
						|
<code>CtClass</code> object is pruned, the bytecode of a method is not
 | 
						|
accessible except method names, signatures, and annotations.
 | 
						|
The pruned <code>CtClass</code> object cannot be defrost again.
 | 
						|
The default value of <code>ClassPool.doPruning</code> is <code>false</code>.
 | 
						|
 | 
						|
<p>To disallow pruning a particular <code>CtClass</code>,
 | 
						|
<code>stopPruning()</code> must be called on that object in advance:
 | 
						|
 | 
						|
<ul><pre>
 | 
						|
CtClasss cc = ...;
 | 
						|
cc.stopPruning(true);
 | 
						|
    :
 | 
						|
cc.writeFile();                             // convert to a class file.
 | 
						|
// cc is not pruned.
 | 
						|
</pre></ul>
 | 
						|
 | 
						|
<p>The <code>CtClass</code> object <code>cc</code> is not pruned.
 | 
						|
Thus it can be defrost after <code>writeFile()</code> is called.
 | 
						|
 | 
						|
<ul><b>Note:</b>
 | 
						|
While debugging, you might want to temporarily stop pruning and freezing
 | 
						|
and write a modified class file to a disk drive.
 | 
						|
<code>debugWriteFile()</code> is a convenient method
 | 
						|
for that purpose.  It stops pruning, writes a class file, defrosts it,
 | 
						|
and turns pruning on again (if it was initially on).
 | 
						|
</ul>
 | 
						|
 | 
						|
 | 
						|
 | 
						|
<h4>Class search path</h4>
 | 
						|
 | 
						|
<p>The default <code>ClassPool</code> returned
 | 
						|
by a static method <code>ClassPool.getDefault()</code>
 | 
						|
searches the same path that the underlying JVM (Java virtual machine) has.
 | 
						|
<em>If a program is running on a web application server such as JBoss and Tomcat,
 | 
						|
the <code>ClassPool</code> object may not be able to find user classes</em>
 | 
						|
since such a web application server uses multiple class loaders as well as
 | 
						|
the system class loader.  In that case, an additional class path must be
 | 
						|
registered to the <code>ClassPool</code>.  Suppose that <code>pool</code>
 | 
						|
refers to a <code>ClassPool</code> object:
 | 
						|
 | 
						|
<ul><pre>
 | 
						|
pool.insertClassPath(new ClassClassPath(this.getClass()));
 | 
						|
</pre></ul>
 | 
						|
 | 
						|
<p>
 | 
						|
This statement registers the class path that was used for loading
 | 
						|
the class of the object that <code>this</code> refers to.
 | 
						|
You can use any <code>Class</code> object as an argument instead of
 | 
						|
<code>this.getClass()</code>.  The class path used for loading the
 | 
						|
class represented by that <code>Class</code> object is registered.
 | 
						|
 | 
						|
<p>
 | 
						|
You can register a directory name as the class search path.
 | 
						|
For example, the following code adds a directory
 | 
						|
<code>/usr/local/javalib</code>
 | 
						|
to the search path:
 | 
						|
 | 
						|
<ul><pre>
 | 
						|
ClassPool pool = ClassPool.getDefault();
 | 
						|
pool.insertClassPath("/usr/local/javalib");
 | 
						|
</pre></ul>
 | 
						|
 | 
						|
<p>The search path that the users can add is not only a directory but also
 | 
						|
a URL:
 | 
						|
 | 
						|
<ul><pre>
 | 
						|
ClassPool pool = ClassPool.getDefault();
 | 
						|
ClassPath cp = new URLClassPath("www.javassist.org", 80, "/java/", "org.javassist.");
 | 
						|
pool.insertClassPath(cp);
 | 
						|
</pre></ul>
 | 
						|
 | 
						|
<p>This program adds "http://www.javassist.org:80/java/" to the class search
 | 
						|
path.  This URL is used only for searching classes belonging to a
 | 
						|
package <code>org.javassist</code>.  For example, to load a class
 | 
						|
<code>org.javassist.test.Main</code>, its class file will be obtained from:
 | 
						|
 | 
						|
<ul><pre>http://www.javassist.org:80/java/org/javassist/test/Main.class
 | 
						|
</pre></ul>
 | 
						|
 | 
						|
<p>Furthermore, you can directly give a byte array
 | 
						|
to a <code>ClassPool</code> object
 | 
						|
and construct a <code>CtClass</code> object from that array.  To do this,
 | 
						|
use <code>ByteArrayClassPath</code>.  For example,
 | 
						|
 | 
						|
<ul><pre>
 | 
						|
ClassPool cp = ClassPool.getDefault();
 | 
						|
byte[] b = <em>a byte array</em>;
 | 
						|
String name = <em>class name</em>;
 | 
						|
cp.insertClassPath(new ByteArrayClassPath(name, b));
 | 
						|
CtClass cc = cp.get(name);
 | 
						|
</pre></ul>
 | 
						|
 | 
						|
<p>The obtained <code>CtClass</code> object represents
 | 
						|
a class defined by the class file specified by <code>b</code>.
 | 
						|
The <code>ClassPool</code> reads a class file from the given
 | 
						|
<code>ByteArrayClassPath</code> if <code>get()</code> is called
 | 
						|
and the class name given to <code>get()</code> is equal to
 | 
						|
one specified by <code>name</code>.
 | 
						|
 | 
						|
<p>If you do not know the fully-qualified name of the class, then you
 | 
						|
can use <code>makeClass()</code> in <code>ClassPool</code>:
 | 
						|
 | 
						|
<ul><pre>
 | 
						|
ClassPool cp = ClassPool.getDefault();
 | 
						|
InputStream ins = <em>an input stream for reading a class file</em>;
 | 
						|
CtClass cc = cp.makeClass(ins);
 | 
						|
</pre></ul>
 | 
						|
 | 
						|
<p><code>makeClass()</code> returns the <code>CtClass</code> object
 | 
						|
constructed from the given input stream.  You can use
 | 
						|
<code>makeClass()</code> for eagerly feeding class files to 
 | 
						|
the <code>ClassPool</code> object.  This might improve performance
 | 
						|
if the search path includes a large jar file.  Since 
 | 
						|
a <code>ClassPool</code> object reads a class file on demand,
 | 
						|
it might repeatedly search the whole jar file for every class file.
 | 
						|
<code>makeClass()</code> can be used for optimizing this search.
 | 
						|
The <code>CtClass</code> constructed by <code>makeClass()</code>
 | 
						|
is kept in the <code>ClassPool</code> object and the class file is never
 | 
						|
read again.
 | 
						|
 | 
						|
<p>The users can extend the class search path.  They can define a new
 | 
						|
class implementing <code>ClassPath</code> interface and give an
 | 
						|
instance of that class to <code>insertClassPath()</code> in
 | 
						|
<code>ClassPool</code>.  This allows a non-standard resource to be
 | 
						|
included in the search path.
 | 
						|
 | 
						|
<p><br>
 | 
						|
 | 
						|
<a name="pool">
 | 
						|
<h2>2. ClassPool</h2>
 | 
						|
 | 
						|
<p>
 | 
						|
A <code>ClassPool</code> object is a container of <code>CtClass</code>
 | 
						|
objects.  Once a <code>CtClass</code> object is created, it is
 | 
						|
recorded in a <code>ClassPool</code> for ever.  This is because a
 | 
						|
compiler may need to access the <code>CtClass</code> object later when
 | 
						|
it compiles source code that refers to the class represented by that
 | 
						|
<code>CtClass</code>.
 | 
						|
 | 
						|
<p>
 | 
						|
For example, suppose that a new method <code>getter()</code> is added
 | 
						|
to a <code>CtClass</code> object representing <code>Point</code>
 | 
						|
class.  Later, the program attempts to compile source code including a
 | 
						|
method call to <code>getter()</code> in <code>Point</code> and use the
 | 
						|
compiled code as the body of a method, which will be added to another
 | 
						|
class <code>Line</code>.  If the <code>CtClass</code> object representing
 | 
						|
<code>Point</code> is lost, the compiler cannot compile the method call
 | 
						|
to <code>getter()</code>.  Note that the original class definition does
 | 
						|
not include <code>getter()</code>.  Therefore, to correctly compile
 | 
						|
such a method call, the <code>ClassPool</code>
 | 
						|
must contain all the instances of <code>CtClass</code> all the time of
 | 
						|
program execution.
 | 
						|
 | 
						|
<a name="avoidmemory">
 | 
						|
<h4>Avoid out of memory</h4>
 | 
						|
</a>
 | 
						|
 | 
						|
<p>
 | 
						|
This specification of <code>ClassPool</code> may cause huge memory
 | 
						|
consumption if the number of <code>CtClass</code> objects becomes
 | 
						|
amazingly large (this rarely happens since Javassist tries to reduce
 | 
						|
memory consumption in <a href="#frozenclasses">various ways</a>).
 | 
						|
To avoid this problem, you
 | 
						|
can explicitly remove an unnecessary <code>CtClass</code> object from
 | 
						|
the <code>ClassPool</code>.  If you call <code>detach()</code> on a
 | 
						|
<code>CtClass</code> object, then that <code>CtClass</code> object is
 | 
						|
removed from the <code>ClassPool</code>.  For example,
 | 
						|
 | 
						|
<ul><pre>
 | 
						|
CtClass cc = ... ;
 | 
						|
cc.writeFile();
 | 
						|
cc.detach();
 | 
						|
</pre></ul>
 | 
						|
 | 
						|
<p>You must not call any method on that
 | 
						|
<code>CtClass</code> object after <code>detach()</code> is called.
 | 
						|
However, you can call <code>get()</code> on <code>ClassPool</code>
 | 
						|
to make a new instance of <code>CtClass</code> representing
 | 
						|
the same class.  If you call <code>get()</code>, the <code>ClassPool</code>
 | 
						|
reads a class file again and newly creates a <code>CtClass</code>
 | 
						|
object, which is returned by <code>get()</code>.
 | 
						|
 | 
						|
<p>
 | 
						|
Another idea is to occasionally replace a <code>ClassPool</code> with
 | 
						|
a new one and discard the old one.  If an old <code>ClassPool</code>
 | 
						|
is garbage collected, the <code>CtClass</code> objects included in
 | 
						|
that <code>ClassPool</code> are also garbage collected.
 | 
						|
To create a new instance of <code>ClassPool</code>, execute the following
 | 
						|
code snippet:
 | 
						|
 | 
						|
<ul><pre>
 | 
						|
ClassPool cp = new ClassPool(true);
 | 
						|
// if needed, append an extra search path by appendClassPath()
 | 
						|
</pre></ul>
 | 
						|
 | 
						|
<p>This creates a <code>ClassPool</code> object that behaves as the
 | 
						|
default <code>ClassPool</code> returned by
 | 
						|
<code>ClassPool.getDefault()</code> does.
 | 
						|
Note that <code>ClassPool.getDefault()</code> is a singleton factory method
 | 
						|
provided for convenience.  It creates a <code>ClassPool</code> object in
 | 
						|
the same way shown above although it keeps a single instance of
 | 
						|
<code>ClassPool</code> and reuses it.
 | 
						|
A <code>ClassPool</code> object returned by <code>getDefault()</code>
 | 
						|
does not have a special role.  <code>getDefault()</code> is a convenience
 | 
						|
method.
 | 
						|
 | 
						|
<p>Note that <code>new ClassPool(true)</code> is a convenient constructor,
 | 
						|
which constructs a <code>ClassPool</code> object and appends the system
 | 
						|
search path to it.  Calling that constructor is
 | 
						|
equivalent to the following code:
 | 
						|
 | 
						|
<ul><pre>
 | 
						|
ClassPool cp = new ClassPool();
 | 
						|
cp.appendSystemPath();  // or append another path by appendClassPath()
 | 
						|
</pre></ul>
 | 
						|
 | 
						|
<h4>Cascaded ClassPools</h4>
 | 
						|
 | 
						|
<p>
 | 
						|
<em>If a program is running on a web application server,</em>
 | 
						|
creating multiple instances of <code>ClassPool</code> might be necessary;
 | 
						|
an instance of <code>ClassPool</code> should be created
 | 
						|
for each class loader (i.e. container).
 | 
						|
The program should create a <code>ClassPool</code> object by not calling
 | 
						|
<code>getDefault()</code> but a constructor of <code>ClassPool</code>.
 | 
						|
 | 
						|
<p>
 | 
						|
Multiple <code>ClassPool</code> objects can be cascaded like
 | 
						|
<code>java.lang.ClassLoader</code>.  For example,
 | 
						|
 | 
						|
<ul><pre>
 | 
						|
ClassPool parent = ClassPool.getDefault();
 | 
						|
ClassPool child = new ClassPool(parent);
 | 
						|
child.insertClassPath("./classes");
 | 
						|
</pre></ul>
 | 
						|
 | 
						|
<p>
 | 
						|
If <code>child.get()</code> is called, the child <code>ClassPool</code>
 | 
						|
first delegates to the parent <code>ClassPool</code>.  If the parent
 | 
						|
<code>ClassPool</code> fails to find a class file, then the child
 | 
						|
<code>ClassPool</code> attempts to find a class file
 | 
						|
under the <code>./classes</code> directory.
 | 
						|
 | 
						|
<p>
 | 
						|
If <code>child.childFirstLookup</code> is true, the child
 | 
						|
<code>ClassPool</code> attempts to find a class file before delegating
 | 
						|
to the parent <code>ClassPool</code>.  For example,
 | 
						|
 | 
						|
<ul><pre>
 | 
						|
ClassPool parent = ClassPool.getDefault();
 | 
						|
ClassPool child = new ClassPool(parent);
 | 
						|
child.appendSystemPath();         // the same class path as the default one.
 | 
						|
child.childFirstLookup = true;    // changes the behavior of the child.
 | 
						|
</pre></ul>
 | 
						|
 | 
						|
<h4>Changing a class name for defining a new class</h4>
 | 
						|
 | 
						|
<p>A new class can be defined as a copy of an existing class.
 | 
						|
The program below does that:
 | 
						|
 | 
						|
<ul><pre>
 | 
						|
ClassPool pool = ClassPool.getDefault();
 | 
						|
CtClass cc = pool.get("Point");
 | 
						|
cc.setName("Pair");
 | 
						|
</pre></ul>
 | 
						|
 | 
						|
<p>This program first obtains the <code>CtClass</code> object for
 | 
						|
class <code>Point</code>.  Then it calls <code>setName()</code> to
 | 
						|
give a new name <code>Pair</code> to that <code>CtClass</code> object.
 | 
						|
After this call, all occurrences of the class name in the class
 | 
						|
definition represented by that <code>CtClass</code> object are changed
 | 
						|
from <code>Point</code> to <code>Pair</code>.  The other part of the
 | 
						|
class definition does not change.
 | 
						|
 | 
						|
<p>Note that <code>setName()</code> in <code>CtClass</code> changes a
 | 
						|
record in the <code>ClassPool</code> object.  From the implementation
 | 
						|
viewpoint, a <code>ClassPool</code> object is a hash table of
 | 
						|
<code>CtClass</code> objects.  <code>setName()</code> changes
 | 
						|
the key associated to the <code>CtClass</code> object in the hash
 | 
						|
table.  The key is changed from the original class name to the new
 | 
						|
class name.
 | 
						|
 | 
						|
<p>Therefore, if <code>get("Point")</code> is later called on the
 | 
						|
<code>ClassPool</code> object again, then it never returns the
 | 
						|
<code>CtClass</code> object that the variable <code>cc</code> refers to.
 | 
						|
The <code>ClassPool</code> object reads
 | 
						|
a class file
 | 
						|
<code>Point.class</code> again and it constructs a new <code>CtClass</code>
 | 
						|
object for class <code>Point</code>.
 | 
						|
This is because the <code>CtClass</code> object associated with the name
 | 
						|
<code>Point</code> does not exist any more.
 | 
						|
See the followings:
 | 
						|
 | 
						|
<ul><pre>
 | 
						|
ClassPool pool = ClassPool.getDefault();
 | 
						|
CtClass cc = pool.get("Point");
 | 
						|
CtClass cc1 = pool.get("Point");   // cc1 is identical to cc.
 | 
						|
cc.setName("Pair");
 | 
						|
CtClass cc2 = pool.get("Pair");    // cc2 is identical to cc.
 | 
						|
CtClass cc3 = pool.get("Point");   // cc3 is not identical to cc.
 | 
						|
</pre></ul>
 | 
						|
 | 
						|
<p><code>cc1</code> and <code>cc2</code> refer to the same instance of
 | 
						|
<code>CtClass</code> that <code>cc</code> does whereas
 | 
						|
<code>cc3</code> does not.  Note that, after
 | 
						|
<code>cc.setName("Pair")</code> is executed, the <code>CtClass</code>
 | 
						|
object that <code>cc</code> and <code>cc1</code> refer to represents
 | 
						|
the <code>Pair</code> class.
 | 
						|
 | 
						|
<p>The <code>ClassPool</code> object is used to maintain one-to-one
 | 
						|
mapping between classes and <code>CtClass</code> objects.  Javassist
 | 
						|
never allows two distinct <code>CtClass</code> objects to represent
 | 
						|
the same class unless two independent <code>ClassPool</code> are created.
 | 
						|
This is a significant feature for consistent program
 | 
						|
transformation.
 | 
						|
 | 
						|
<p>To create another copy of the default instance of
 | 
						|
<code>ClassPool</code>, which is returned by
 | 
						|
<code>ClassPool.getDefault()</code>, execute the following code
 | 
						|
snippet (this code was already <a href="#avoidmemory">shown above</a>):
 | 
						|
 | 
						|
<ul><pre>
 | 
						|
ClassPool cp = new ClassPool(true);
 | 
						|
</pre></ul>
 | 
						|
 | 
						|
<p>If you have two <code>ClassPool</code> objects, then you can
 | 
						|
obtain, from each <code>ClassPool</code>, a distinct
 | 
						|
<code>CtClass</code> object representing the same class file.  You can
 | 
						|
differently modify these <code>CtClass</code> objects to generate
 | 
						|
different versions of the class.
 | 
						|
 | 
						|
<h4>Renaming a frozen class for defining a new class</h4>
 | 
						|
 | 
						|
<p>Once a <code>CtClass</code> object is converted into a class file
 | 
						|
by <code>writeFile()</code> or <code>toBytecode()</code>, Javassist
 | 
						|
rejects further modifications of that <code>CtClass</code> object.
 | 
						|
Hence, after the <code>CtClass</code> object representing <code>Point</code>
 | 
						|
class is converted into a class file, you cannot define <code>Pair</code>
 | 
						|
class as a copy of <code>Point</code> since executing <code>setName()</code>
 | 
						|
on <code>Point</code> is rejected.
 | 
						|
The following code snippet is wrong:
 | 
						|
 | 
						|
<ul><pre>
 | 
						|
ClassPool pool = ClassPool.getDefault();
 | 
						|
CtClass cc = pool.get("Point");
 | 
						|
cc.writeFile();
 | 
						|
cc.setName("Pair");    // wrong since writeFile() has been called.
 | 
						|
</pre></ul>
 | 
						|
 | 
						|
<p>To avoid this restriction, you should call <code>getAndRename()</code>
 | 
						|
in <code>ClassPool</code>.  For example,
 | 
						|
 | 
						|
<ul><pre>
 | 
						|
ClassPool pool = ClassPool.getDefault();
 | 
						|
CtClass cc = pool.get("Point");
 | 
						|
cc.writeFile();
 | 
						|
CtClass cc2 = pool.getAndRename("Point", "Pair");
 | 
						|
</pre></ul>
 | 
						|
 | 
						|
<p>If <code>getAndRename()</code> is called, the <code>ClassPool</code>
 | 
						|
first reads <code>Point.class</code> for creating a new <code>CtClass</code>
 | 
						|
object representing <code>Point</code> class.  However, it renames that
 | 
						|
<code>CtClass</code> object from <code>Point</code> to <code>Pair</code> before
 | 
						|
it records that <code>CtClass</code> object in a hash table.
 | 
						|
Thus <code>getAndRename()</code>
 | 
						|
can be executed after <code>writeFile()</code> or <code>toBytecode()</code>
 | 
						|
is called on the the <code>CtClass</code> object representing <code>Point</code>
 | 
						|
class.
 | 
						|
 | 
						|
<p><br>
 | 
						|
 | 
						|
<a name="load">
 | 
						|
<h2>3. Class loader</h2>
 | 
						|
 | 
						|
<p>If what classes must be modified is known in advance,
 | 
						|
the easiest way for modifying the classes is as follows:
 | 
						|
 | 
						|
<ul><li>1. Get a <code>CtClass</code> object by calling
 | 
						|
        <code>ClassPool.get()</code>,
 | 
						|
    <li>2. Modify it, and
 | 
						|
    <li>3. Call <code>writeFile()</code> or <code>toBytecode()</code>
 | 
						|
           on that <code>CtClass</code> object to obtain a modified class file.
 | 
						|
</ul>
 | 
						|
 | 
						|
<p>If whether a class is modified or not is determined at load time,
 | 
						|
the users must make Javassist collaborate with a class loader.
 | 
						|
Javassist can be used with a class loader so that bytecode can be
 | 
						|
modified at load time.  The users of Javassist can define their own
 | 
						|
version of class loader but they can also use a class loader provided
 | 
						|
by Javassist.
 | 
						|
 | 
						|
 | 
						|
<p><br>
 | 
						|
 | 
						|
<a name="toclass">
 | 
						|
<h3>3.1 The <code>toClass</code> method in <code>CtClass</code></h3>
 | 
						|
</a>
 | 
						|
 | 
						|
<p>The <code>CtClass</code> provides a convenience method
 | 
						|
<code>toClass()</code>, which requests the context class loader for
 | 
						|
the current thread to load the class represented by the <code>CtClass</code>
 | 
						|
object.  To call this method, the caller must have appropriate permission;
 | 
						|
otherwise, a <code>SecurityException</code> may be thrown.
 | 
						|
 | 
						|
<p>The following program shows how to use <code>toClass()</code>:
 | 
						|
 | 
						|
<ul><pre>
 | 
						|
public class Hello {
 | 
						|
    public void say() {
 | 
						|
        System.out.println("Hello");
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
public class Test {
 | 
						|
    public static void main(String[] args) throws Exception {
 | 
						|
        ClassPool cp = ClassPool.getDefault();
 | 
						|
        CtClass cc = cp.get("Hello");
 | 
						|
        CtMethod m = cc.getDeclaredMethod("say");
 | 
						|
        m.insertBefore("{ System.out.println(\"Hello.say():\"); }");
 | 
						|
        Class c = cc.toClass();
 | 
						|
        Hello h = (Hello)c.newInstance();
 | 
						|
        h.say();
 | 
						|
    }
 | 
						|
}
 | 
						|
</pre></ul>
 | 
						|
 | 
						|
<p><code>Test.main()</code> inserts a call to <code>println()</code>
 | 
						|
in the method body of <code>say()</code> in <code>Hello</code>.  Then
 | 
						|
it constructs an instance of the modified <code>Hello</code> class
 | 
						|
and calls <code>say()</code> on that instance.
 | 
						|
 | 
						|
<p>Note that the program above depends on the fact that the
 | 
						|
<code>Hello</code> class is never loaded before <code>toClass()</code>
 | 
						|
is invoked.  If not, the JVM would load the original
 | 
						|
<code>Hello</code> class before <code>toClass()</code> requests to
 | 
						|
load the modified <code>Hello</code> class.  Hence loading the
 | 
						|
modified <code>Hello</code> class would be failed
 | 
						|
(<code>LinkageError</code> is thrown).  For example, if
 | 
						|
<code>main()</code> in <code>Test</code> is something like this:
 | 
						|
 | 
						|
<ul><pre>
 | 
						|
public static void main(String[] args) throws Exception {
 | 
						|
    Hello orig = new Hello();
 | 
						|
    ClassPool cp = ClassPool.getDefault();
 | 
						|
    CtClass cc = cp.get("Hello");
 | 
						|
        :
 | 
						|
}
 | 
						|
</pre></ul>
 | 
						|
 | 
						|
<p>then the original <code>Hello</code> class is loaded at the first
 | 
						|
line of <code>main</code> and the call to <code>toClass()</code>
 | 
						|
throws an exception since the class loader cannot load two different
 | 
						|
versions of the <code>Hello</code> class at the same time.
 | 
						|
 | 
						|
<p><em>If the program is running on some application server such as
 | 
						|
JBoss and Tomcat,</em> the context class loader used by
 | 
						|
<code>toClass()</code> might be inappropriate.  In this case, you
 | 
						|
would see an unexpected <code>ClassCastException</code>.  To avoid
 | 
						|
this exception, you must explicitly give an appropriate class loader
 | 
						|
to <code>toClass()</code>.  For example, if <code>bean</code> is your
 | 
						|
session bean object, then the following code:
 | 
						|
 | 
						|
<ul><pre>CtClass cc = ...;
 | 
						|
Class c = cc.toClass(bean.getClass().getClassLoader());
 | 
						|
</pre></ul>
 | 
						|
 | 
						|
<p>would work.  You should give <code>toClass()</code> the class loader
 | 
						|
that has loaded your program (in the above example, the class of
 | 
						|
the <code>bean</code> object).
 | 
						|
 | 
						|
<p><code>toClass()</code> is provided for convenience.  If you need
 | 
						|
more complex functionality, you should write your own class loader.
 | 
						|
 | 
						|
<p><br>
 | 
						|
 | 
						|
<h3>3.2 Class loading in Java</h3>
 | 
						|
 | 
						|
<p>In Java, multiple class loaders can coexist and
 | 
						|
each class loader creates its own name space.
 | 
						|
Different class loaders can load different class files with the
 | 
						|
same class name.  The loaded two classes are regarded as different
 | 
						|
ones.  This feature enables us to run multiple application programs
 | 
						|
on a single JVM even if these programs include different classes
 | 
						|
with the same name.
 | 
						|
 | 
						|
<ul>
 | 
						|
<b>Note:</b> The JVM does not allow dynamically reloading a class.
 | 
						|
Once a class loader loads a class, it cannot reload a modified
 | 
						|
version of that class during runtime.  Thus, you cannot alter
 | 
						|
the definition of a class after the JVM loads it.
 | 
						|
However, the JPDA (Java Platform Debugger Architecture) provides
 | 
						|
limited ability for reloading a class.
 | 
						|
See <a href="#hotswap">Section 3.6</a>.
 | 
						|
</ul>
 | 
						|
 | 
						|
<p>If the same class file is loaded by two distinct class loaders,
 | 
						|
the JVM makes two distinct classes with the same name and definition.
 | 
						|
The two classes are regarded as different ones.
 | 
						|
Since the two classes are not identical, an instance of one class is
 | 
						|
not assignable to a variable of the other class.  The cast operation
 | 
						|
between the two classes fails
 | 
						|
and throws a <em><code>ClassCastException</code></em>.
 | 
						|
 | 
						|
<p>For example, the following code snippet throws an exception:
 | 
						|
 | 
						|
<ul><pre>
 | 
						|
MyClassLoader myLoader = new MyClassLoader();
 | 
						|
Class clazz = myLoader.loadClass("Box");
 | 
						|
Object obj = clazz.newInstance();
 | 
						|
Box b = (Box)obj;    // this always throws ClassCastException.
 | 
						|
</pre></ul>
 | 
						|
 | 
						|
<p>
 | 
						|
The <code>Box</code> class is loaded by two class loaders.
 | 
						|
Suppose that a class loader CL loads a class including this code snippet.
 | 
						|
Since this code snippet refers to <code>MyClassLoader</code>,
 | 
						|
<code>Class</code>, <code>Object</code>, and <code>Box</code>,
 | 
						|
CL also loads these classes (unless it delegates to another class loader).
 | 
						|
Hence the type of the variable <code>b</code> is the <code>Box</code>
 | 
						|
class loaded by CL.
 | 
						|
On the other hand, <code>myLoader</code> also loads the <code>Box</code>
 | 
						|
class.  The object <code>obj</code> is an instance of
 | 
						|
the <code>Box</code> class loaded by <code>myLoader</code>.
 | 
						|
Therefore, the last statement always throws a
 | 
						|
<code>ClassCastException</code> since the class of <code>obj</code> is
 | 
						|
a different verison of the <code>Box</code> class from one used as the
 | 
						|
type of the variable <code>b</code>.
 | 
						|
 | 
						|
<p>Multiple class loaders form a tree structure.
 | 
						|
Each class loader except the bootstrap loader has a
 | 
						|
parent class loader, which has normally loaded the class of that child
 | 
						|
class loader.  Since the request to load a class can be delegated along this
 | 
						|
hierarchy of class loaders, a class may be loaded by a class loader that
 | 
						|
you do not request the class loading.
 | 
						|
Therefore, the class loader that has been requested to load a class C
 | 
						|
may be different from the loader that actually loads the class C.
 | 
						|
For distinction, we call the former loader <em>the initiator of C</em>
 | 
						|
and we call the latter loader <em>the real loader of C</em>.
 | 
						|
 | 
						|
<p>
 | 
						|
Furthermore, if a class loader CL requested to load a class C
 | 
						|
(the initiator of C) delegates
 | 
						|
to the parent class loader PL, then the class loader CL is never requested
 | 
						|
to load any classes referred to in the definition of the class C.
 | 
						|
CL is not the initiator of those classes.
 | 
						|
Instead, the parent class loader PL becomes their initiators
 | 
						|
and it is requested to load them.
 | 
						|
<em>The classes that the definition of a class C referes to are loaded by
 | 
						|
the real loader of C.</em>
 | 
						|
 | 
						|
<p>To understand this behavior, let's consider the following example.
 | 
						|
 | 
						|
<ul><pre>
 | 
						|
public class Point {    // loaded by PL
 | 
						|
    private int x, y;
 | 
						|
    public int getX() { return x; }
 | 
						|
        :
 | 
						|
}
 | 
						|
 | 
						|
public class Box {      // the initiator is L but the real loader is PL
 | 
						|
    private Point upperLeft, size;
 | 
						|
    public int getBaseX() { return upperLeft.x; }
 | 
						|
        :
 | 
						|
}
 | 
						|
 | 
						|
public class Window {    // loaded by a class loader L
 | 
						|
    private Box box;
 | 
						|
    public int getBaseX() { return box.getBaseX(); }
 | 
						|
}</pre></ul>
 | 
						|
 | 
						|
<p>Suppose that a class <code>Window</code> is loaded by a class loader L.
 | 
						|
Both the initiator and the real loader of <code>Window</code> are L.
 | 
						|
Since the definition of <code>Window</code> refers to <code>Box</code>,
 | 
						|
the JVM will request L to load <code>Box</code>.
 | 
						|
Here, suppose that L delegates this task to the parent class loader PL.
 | 
						|
The initiator of <code>Box</code> is L but the real loader is PL.
 | 
						|
In this case, the initiator of <code>Point</code> is not L but PL
 | 
						|
since it is the same as the real loader of <code>Box</code>.
 | 
						|
Thus L is never requested to load <code>Point</code>.
 | 
						|
 | 
						|
<p>Next, let's consider a slightly modified example.
 | 
						|
 | 
						|
<ul><pre>
 | 
						|
public class Point {
 | 
						|
    private int x, y;
 | 
						|
    public int getX() { return x; }
 | 
						|
        :
 | 
						|
}
 | 
						|
 | 
						|
public class Box {      // the initiator is L but the real loader is PL
 | 
						|
    private Point upperLeft, size;
 | 
						|
    public Point getSize() { return size; }
 | 
						|
        :
 | 
						|
}
 | 
						|
 | 
						|
public class Window {    // loaded by a class loader L
 | 
						|
    private Box box;
 | 
						|
    public boolean widthIs(int w) {
 | 
						|
        Point p = box.getSize();
 | 
						|
        return w == p.getX();
 | 
						|
    }
 | 
						|
}</pre></ul>
 | 
						|
 | 
						|
<p>Now, the definition of <code>Window</code> also refers to
 | 
						|
<code>Point</code>.  In this case, the class loader L must
 | 
						|
also delegate to PL if it is requested to load <code>Point</code>.
 | 
						|
<em>You must avoid having two class loaders doubly load the same
 | 
						|
class.</em>  One of the two loaders must delegate to
 | 
						|
the other.
 | 
						|
 | 
						|
<p>
 | 
						|
If L does not delegate to PL when <code>Point</code>
 | 
						|
is loaded, <code>widthIs()</code> would throw a ClassCastException.
 | 
						|
Since the real loader of <code>Box</code> is PL,
 | 
						|
<code>Point</code> referred to in <code>Box</code> is also loaded by PL.
 | 
						|
Therefore, the resulting value of <code>getSize()</code>
 | 
						|
is an instance of <code>Point</code> loaded by PL
 | 
						|
whereas the type of the variable <code>p</code> in <code>widthIs()</code>
 | 
						|
is <code>Point</code> loaded by L.
 | 
						|
The JVM regards them as distinct types and thus it throws an exception
 | 
						|
because of type mismatch.
 | 
						|
 | 
						|
<p>This behavior is somewhat inconvenient but necessary.
 | 
						|
If the following statement:
 | 
						|
 | 
						|
<ul><pre>
 | 
						|
Point p = box.getSize();
 | 
						|
</pre></ul>
 | 
						|
 | 
						|
<p>did not throw an exception,
 | 
						|
then the programmer of <code>Window</code> could break the encapsulation
 | 
						|
of <code>Point</code> objects.
 | 
						|
For example, the field <code>x</code>
 | 
						|
is private in <code>Point</code> loaded by PL.
 | 
						|
However, the <code>Window</code> class could
 | 
						|
directly access the value of <code>x</code>
 | 
						|
if L loads <code>Point</code> with the following definition:
 | 
						|
 | 
						|
<ul><pre>
 | 
						|
public class Point {
 | 
						|
    public int x, y;    // not private
 | 
						|
    public int getX() { return x; }
 | 
						|
        :
 | 
						|
}
 | 
						|
</pre></ul>
 | 
						|
 | 
						|
<p>
 | 
						|
For more details of class loaders in Java, the following paper would
 | 
						|
be helpful:
 | 
						|
 | 
						|
<ul>Sheng Liang and Gilad Bracha,
 | 
						|
"Dynamic Class Loading in the Java Virtual Machine",
 | 
						|
<br><i>ACM OOPSLA'98</i>, pp.36-44, 1998.</ul>
 | 
						|
 | 
						|
<p><br>
 | 
						|
 | 
						|
<h3>3.3 Using <code>javassist.Loader</code></h3>
 | 
						|
 | 
						|
<p>Javassist provides a class loader
 | 
						|
<code>javassist.Loader</code>.  This class loader uses a
 | 
						|
<code>javassist.ClassPool</code> object for reading a class file.
 | 
						|
 | 
						|
<p>For example, <code>javassist.Loader</code> can be used for loading
 | 
						|
a particular class modified with Javassist.
 | 
						|
 | 
						|
<ul><pre>
 | 
						|
import javassist.*;
 | 
						|
import test.Rectangle;
 | 
						|
 | 
						|
public class Main {
 | 
						|
  public static void main(String[] args) throws Throwable {
 | 
						|
     ClassPool pool = ClassPool.getDefault();
 | 
						|
     Loader cl = new Loader(pool);
 | 
						|
 | 
						|
     CtClass ct = pool.get("test.Rectangle");
 | 
						|
     ct.setSuperclass(pool.get("test.Point"));
 | 
						|
 | 
						|
     Class c = cl.loadClass("test.Rectangle");
 | 
						|
     Object rect = c.newInstance();
 | 
						|
         :
 | 
						|
  }
 | 
						|
}
 | 
						|
</pre></ul>
 | 
						|
 | 
						|
<p>This program modifies a class <code>test.Rectangle</code>.  The
 | 
						|
superclass of <code>test.Rectangle</code> is set to a
 | 
						|
<code>test.Point</code> class.  Then this program loads the modified
 | 
						|
class, and creates a new instance of the
 | 
						|
<code>test.Rectangle</code> class.
 | 
						|
 | 
						|
<p>If the users want to modify a class on demand when it is loaded,
 | 
						|
the users can add an event listener to a <code>javassist.Loader</code>.
 | 
						|
The added event listener is
 | 
						|
notified when the class loader loads a class.
 | 
						|
The event-listener class must implement the following interface:
 | 
						|
 | 
						|
<ul><pre>public interface Translator {
 | 
						|
    public void start(ClassPool pool)
 | 
						|
        throws NotFoundException, CannotCompileException;
 | 
						|
    public void onLoad(ClassPool pool, String classname)
 | 
						|
        throws NotFoundException, CannotCompileException;
 | 
						|
}</pre></ul>
 | 
						|
 | 
						|
<p>The method <code>start()</code> is called when this event listener
 | 
						|
is added to a <code>javassist.Loader</code> object by
 | 
						|
<code>addTranslator()</code> in <code>javassist.Loader</code>.  The
 | 
						|
method <code>onLoad()</code> is called before
 | 
						|
<code>javassist.Loader</code> loads a class.  <code>onLoad()</code>
 | 
						|
can modify the definition of the loaded class.
 | 
						|
 | 
						|
<p>For example, the following event listener changes all classes
 | 
						|
to public classes just before they are loaded.
 | 
						|
 | 
						|
<ul><pre>public class MyTranslator implements Translator {
 | 
						|
    void start(ClassPool pool)
 | 
						|
        throws NotFoundException, CannotCompileException {}
 | 
						|
    void onLoad(ClassPool pool, String classname)
 | 
						|
        throws NotFoundException, CannotCompileException
 | 
						|
    {
 | 
						|
        CtClass cc = pool.get(classname);
 | 
						|
        cc.setModifiers(Modifier.PUBLIC);
 | 
						|
    }
 | 
						|
}</pre></ul>
 | 
						|
 | 
						|
<p>Note that <code>onLoad()</code> does not have to call
 | 
						|
<code>toBytecode()</code> or <code>writeFile()</code> since
 | 
						|
<code>javassist.Loader</code> calls these methods to obtain a class
 | 
						|
file.
 | 
						|
 | 
						|
<p>To run an application class <code>MyApp</code> with a
 | 
						|
<code>MyTranslator</code> object, write a main class as following:
 | 
						|
 | 
						|
<ul><pre>
 | 
						|
import javassist.*;
 | 
						|
 | 
						|
public class Main2 {
 | 
						|
  public static void main(String[] args) throws Throwable {
 | 
						|
     Translator t = new MyTranslator();
 | 
						|
     ClassPool pool = ClassPool.getDefault();
 | 
						|
     Loader cl = new Loader();
 | 
						|
     cl.addTranslator(pool, t);
 | 
						|
     cl.run("MyApp", args);
 | 
						|
  }
 | 
						|
}
 | 
						|
</pre></ul>
 | 
						|
 | 
						|
<p>To run this program, do:
 | 
						|
 | 
						|
<ul><pre>
 | 
						|
% java Main2 <i>arg1</i> <i>arg2</i>...
 | 
						|
</pre></ul>
 | 
						|
 | 
						|
<p>The class <code>MyApp</code> and the other application classes
 | 
						|
are translated by <code>MyTranslator</code>.
 | 
						|
 | 
						|
<p>Note that <em>application</em> classes like <code>MyApp</code> cannot
 | 
						|
access the <em>loader</em> classes such as <code>Main2</code>,
 | 
						|
<code>MyTranslator</code>, and <code>ClassPool</code> because they
 | 
						|
are loaded by different loaders.  The application classes are loaded
 | 
						|
by <code>javassist.Loader</code> whereas the loader classes such as
 | 
						|
<code>Main2</code> are by the default Java class loader.
 | 
						|
 | 
						|
<p><code>javassist.Loader</code> searches for classes in a different
 | 
						|
order from <code>java.lang.ClassLoader</code>.
 | 
						|
<code>ClassLoader</code> first delegates the loading operations to
 | 
						|
the parent class loader and then attempts to load the classes
 | 
						|
only if the parent class loader cannot find them.
 | 
						|
On the other hand,
 | 
						|
<code>javassist.Loader</code> attempts
 | 
						|
to load the classes before delegating to the parent class loader.
 | 
						|
It delegates only if:
 | 
						|
 | 
						|
<ul><li>the classes are not found by calling <code>get()</code> on
 | 
						|
a <code>ClassPool</code> object, or
 | 
						|
 | 
						|
<p><li>the classes have been specified by using
 | 
						|
<code>delegateLoadingOf()</code>
 | 
						|
to be loaded by the parent class loader.
 | 
						|
</ul>
 | 
						|
 | 
						|
<p>This search order allows loading modified classes by Javassist.
 | 
						|
However, it delegates to the parent class loader if it fails
 | 
						|
to find modified classes for some reason.  Once a class is loaded by
 | 
						|
the parent class loader, the other classes referred to in that class will be
 | 
						|
also loaded by the parent class loader and thus they are never modified.
 | 
						|
Recall that all the classes referred to in a class C are loaded by the
 | 
						|
real loader of C.
 | 
						|
<em>If your program fails to load a modified class,</em> you should
 | 
						|
make sure whether all the classes using that class have been loaded by
 | 
						|
<code>javassist.Loader</code>.
 | 
						|
 | 
						|
<p><br>
 | 
						|
 | 
						|
<h3>3.4 Writing a class loader</h3>
 | 
						|
 | 
						|
<p>A simple class loader using Javassist is as follows:
 | 
						|
 | 
						|
<ul><pre>import javassist.*;
 | 
						|
 | 
						|
public class SampleLoader extends ClassLoader {
 | 
						|
    /* Call MyApp.main().
 | 
						|
     */
 | 
						|
    public static void main(String[] args) throws Throwable {
 | 
						|
        SampleLoader s = new SampleLoader();
 | 
						|
        Class c = s.loadClass("MyApp");
 | 
						|
        c.getDeclaredMethod("main", new Class[] { String[].class })
 | 
						|
         .invoke(null, new Object[] { args });
 | 
						|
    }
 | 
						|
 | 
						|
    private ClassPool pool;
 | 
						|
 | 
						|
    public SampleLoader() throws NotFoundException {
 | 
						|
        pool = new ClassPool();
 | 
						|
        pool.insertClassPath("./class"); // <em>MyApp.class must be there.</em>
 | 
						|
    }
 | 
						|
 | 
						|
    /* Finds a specified class.
 | 
						|
     * The bytecode for that class can be modified.
 | 
						|
     */
 | 
						|
    protected Class findClass(String name) throws ClassNotFoundException {
 | 
						|
        try {
 | 
						|
            CtClass cc = pool.get(name);
 | 
						|
            // <em>modify the CtClass object here</em>
 | 
						|
            byte[] b = cc.toBytecode();
 | 
						|
            return defineClass(name, b, 0, b.length);
 | 
						|
        } catch (NotFoundException e) {
 | 
						|
            throw new ClassNotFoundException();
 | 
						|
        } catch (IOException e) {
 | 
						|
            throw new ClassNotFoundException();
 | 
						|
        } catch (CannotCompileException e) {
 | 
						|
            throw new ClassNotFoundException();
 | 
						|
        }
 | 
						|
    }
 | 
						|
}</pre></ul>
 | 
						|
 | 
						|
<p>The class <code>MyApp</code> is an application program.
 | 
						|
To execute this program, first put the class file under the
 | 
						|
<code>./class</code> directory, which must <em>not</em> be included
 | 
						|
in the class search path.  Otherwise, <code>MyApp.class</code> would
 | 
						|
be loaded by the default system class loader, which is the parent
 | 
						|
loader of <code>SampleLoader</code>.
 | 
						|
The directory name <code>./class</code> is specified by
 | 
						|
<code>insertClassPath()</code> in the constructor.
 | 
						|
You can choose a different name instead of <code>./class</code> if you want.
 | 
						|
Then do as follows:
 | 
						|
 | 
						|
<ul><code>% java SampleLoader</code></ul>
 | 
						|
 | 
						|
<p>The class loader loads the class <code>MyApp</code>
 | 
						|
(<code>./class/MyApp.class</code>) and calls
 | 
						|
<code>MyApp.main()</code> with the command line parameters.
 | 
						|
 | 
						|
<p>This is the simplest way of using Javassist.  However, if you write
 | 
						|
a more complex class loader, you may need detailed knowledge of
 | 
						|
Java's class loading mechanism.  For example, the program above puts the
 | 
						|
<code>MyApp</code> class in a name space separated from the name space
 | 
						|
that the class <code>SampleLoader</code> belongs to because the two
 | 
						|
classes are loaded by different class loaders.
 | 
						|
Hence, the
 | 
						|
<code>MyApp</code> class cannot directly access the class
 | 
						|
<code>SampleLoader</code>.
 | 
						|
 | 
						|
<p><br>
 | 
						|
 | 
						|
<h3>3.5 Modifying a system class</h3>
 | 
						|
 | 
						|
<p>The system classes like <code>java.lang.String</code> cannot be
 | 
						|
loaded by a class loader other than the system class loader.
 | 
						|
Therefore, <code>SampleLoader</code> or <code>javassist.Loader</code>
 | 
						|
shown above cannot modify the system classes at loading time.
 | 
						|
 | 
						|
<p>If your application needs to do that, the system classes must be
 | 
						|
<em>statically</em> modified.  For example, the following program
 | 
						|
adds a new field <code>hiddenValue</code> to <code>java.lang.String</code>:
 | 
						|
 | 
						|
<ul><pre>ClassPool pool = ClassPool.getDefault();
 | 
						|
CtClass cc = pool.get("java.lang.String");
 | 
						|
CtField f = new CtField(CtClass.intType, "hiddenValue", cc);
 | 
						|
f.setModifiers(Modifier.PUBLIC);
 | 
						|
cc.addField(f);
 | 
						|
cc.writeFile(".");</pre></ul>
 | 
						|
 | 
						|
<p>This program produces a file <code>"./java/lang/String.class"</code>.
 | 
						|
 | 
						|
<p>To run your program <code>MyApp</code>
 | 
						|
with this modified <code>String</code> class, do as follows:
 | 
						|
 | 
						|
<ul><pre>
 | 
						|
% java -Xbootclasspath/p:. MyApp <i>arg1</i> <i>arg2</i>...
 | 
						|
</pre></ul>
 | 
						|
 | 
						|
<p>Suppose that the definition of <code>MyApp</code> is as follows:
 | 
						|
 | 
						|
<ul><pre>public class MyApp {
 | 
						|
    public static void main(String[] args) throws Exception {
 | 
						|
        System.out.println(String.class.getField("hiddenValue").getName());
 | 
						|
    }
 | 
						|
}</pre></ul>
 | 
						|
 | 
						|
<p>If the modified <code>String</code> class is correctly loaded,
 | 
						|
<code>MyApp</code> prints <code>hiddenValue</code>.
 | 
						|
 | 
						|
<p><i>Note: Applications that use this technique for the purpose of
 | 
						|
overriding a system class in <code>rt.jar</code> should not be
 | 
						|
deployed as doing so would contravene the Java 2 Runtime Environment
 | 
						|
binary code license.</i>
 | 
						|
 | 
						|
<p><br>
 | 
						|
 | 
						|
<a name="hotswap">
 | 
						|
<h3>3.6 Reloading a class at runtime</h3></a>
 | 
						|
 | 
						|
<p>If the JVM is launched with the JPDA (Java Platform Debugger
 | 
						|
Architecture) enabled, a class is dynamically reloadable.  After the
 | 
						|
JVM loads a class, the old version of the class definition can be
 | 
						|
unloaded and a new one can be reloaded again.  That is, the definition
 | 
						|
of that class can be dynamically modified during runtime.  However,
 | 
						|
the new class definition must be somewhat compatible to the old one.
 | 
						|
<em>The JVM does not allow schema changes between the two versions.</em>
 | 
						|
They have the same set of methods and fields.
 | 
						|
 | 
						|
<p>Javassist provides a convenient class for reloading a class at runtime.
 | 
						|
For more information, see the API documentation of
 | 
						|
<code>javassist.tools.HotSwapper</code>.
 | 
						|
 | 
						|
<p><br>
 | 
						|
 | 
						|
<a href="tutorial2.html">Next page</a>
 | 
						|
 | 
						|
<hr>
 | 
						|
Java(TM) is a trademark of Sun Microsystems, Inc.<br>
 | 
						|
Copyright (C) 2000-2015 by Shigeru Chiba, All rights reserved.
 | 
						|
</body>
 | 
						|
</html>
 |