aboutsummaryrefslogtreecommitdiffstats
path: root/tutorial/tutorial.html
diff options
context:
space:
mode:
authorchiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>2003-04-23 17:08:37 +0000
committerchiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>2003-04-23 17:08:37 +0000
commitcdeddfd6fc34a06734f9fa525cf5c7437a6c8fb6 (patch)
tree0471a4d9b985b11969ecd6f521f660e3d468f1d1 /tutorial/tutorial.html
parentfb431982111b03608b888953f7ed8ba7e98f421c (diff)
downloadjavassist-cdeddfd6fc34a06734f9fa525cf5c7437a6c8fb6.tar.gz
javassist-cdeddfd6fc34a06734f9fa525cf5c7437a6c8fb6.zip
Changed the copyright notices and removed tab characters.
git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@9 30ef5769-5b8d-40dd-aea6-55b5d6557bb3
Diffstat (limited to 'tutorial/tutorial.html')
-rw-r--r--tutorial/tutorial.html1148
1 files changed, 588 insertions, 560 deletions
diff --git a/tutorial/tutorial.html b/tutorial/tutorial.html
index 3fac03ee..29fcaec4 100644
--- a/tutorial/tutorial.html
+++ b/tutorial/tutorial.html
@@ -1,560 +1,588 @@
-<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 bytecode</a>
-<br>2. <a href="#def">Defining a new class</a>
-<br>3. <a href="#mod">Modifying a class at load time</a>
-<br>4. <a href="#load">Class loader</a>
-<br>5. <a href="tutorial2.html#intro">Introspection and customization</a>
-</ul>
-
-<p><br>
-
-<a name="read">
-<h2>1. Reading 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> 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"));
-pool.writeFile("test.Rectangle"); // or simply, 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 contains the constructed object until it is written out
-to a file or an output stream.
-
-<p>To modify the definition of a class, the users must first obtain a
-reference to the <code>CtClass</code> object representing that class.
-<code>ClassPool.get()</code> is used for this purpose.
-In the case of the program 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>. Then 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>ClassPool.writeFile()</code> is finally called.
-
-<p>Note that <code>writeFile()</code> is a method declared in not
-<code>CtClass</code> but <code>ClassPool</code>.
-If this method is called, the <code>ClassPool</code>
-finds a <code>CtClass</code> object specified with a class name
-among the objects that the <code>ClassPool</code> contains.
-Then it translates that <code>CtClass</code> object into a class file
-and writes it on a local disk.
-
-<p>There is also <code>writeFile()</code> defined in <code>CtClass</code>.
-Thus, the last line in the program above can be rewritten into:
-
-<ul><pre>cc.writeFile();</pre></ul>
-
-<p>This method is a convenient method for invoking <code>writeFile()</code>
-in <code>ClassPool</code> with the name of the class represented by
-<code>cc</code>.
-
-<p>Javassist also provides a method for directly obtaining the
-modified bytecode. To do this, call <code>write()</code>:
-
-<ul><pre>
-byte[] b = pool.write("test.Rectangle");
-</pre></ul>
-
-<p>The contents of the class file for <code>test.Rectangle</code> are
-assigned to a variable <code>b</code> in the form of byte array.
-<code>writeFile()</code> also internally calls <code>write()</code>
-to obtain the byte array written in a class file.
-
-<p>The default <code>ClassPool</code> returned
-by a static method <code>ClassPool.getDefault()</code>
-searches the same path as the underlying JVM.
-The users can expand this class search path if needed.
-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.foo.com", 80, "/java/", "com.foo.");
-pool.insertClassPath(cp);
-</pre></ul>
-
-<p>This program adds "http://www.foo.com:80/java/" to the class search
-path. This URL is used only for searching classes belonging to a
-package <code>com.foo</code>.
-
-<p>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>.
-
-
-<p>Since <code>ClassPath</code> is an interface, the users can define
-a new class implementing this interface and they can add an instance
-of that class so that a class file is obtained from a non-standard resource.
-
-<p><br>
-
-<a name="def">
-<h2>2. Defining a new class</h2>
-
-<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.
-
-<p>A new class can be also defined as a copy of an existing class.
-The program below does that:
-
-<ul><pre>
-ClassPool pool = ClassPool.getDefault();
-CtClass cc = pool.makeClass("Point");
-cc.setName("Pair");
-</pre></ul>
-
-<p>This program first obtains the <code>CtClass</code> object
-for class <code>Point</code>. Then it gives a new name <code>Pair</code>
-to that <code>CtClass</code> object.
-If <code>get("Point")</code> is called on the <code>ClassPool</code>
-object, then a class file <code>Point.class</code> is read again and
-a new <code>CtClass</code> object for class <code>Point</code> is constructed
-again.
-
-<ul><pre>
-ClassPool pool = ClassPool.getDefault();
-CtClass cc = pool.makeClass("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><br>
-
-<a name="mod">
-<h2>3. Modifying a class at load time</h2>
-
-<p>If what classes are 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>ClassPool.write()</code> or <code>writeFile()</code>.
-</ul>
-
-<p>If whether a class is modified or not is determined at load time,
-the users can write an event listener so that it is notified
-when a class is loaded into the JVM.
-A class loader (<code>java.lang.ClassLoader</code>) working with
-Javassist must call <code>ClassPool.write()</code> for obtaining
-a class file. The users can write an event listener so that it is
-notified when the class loader calls <code>ClassPool.write()</code>.
-The event-listener class must implement the following interface:
-
-<ul><pre>public interface Translator {
- public void start(ClassPool pool)
- throws NotFoundException, CannotCompileException;
- public void onWrite(ClassPool pool, String classname)
- throws NotFoundException, CannotCompileException;
-}</pre></ul>
-
-<p>The method <code>start()</code> is called when this event listener
-is registered to a <code>ClassPool</code> object.
-The method <code>onWrite()</code> is called when <code>write()</code>
-(or similar methods) is called on the <code>ClassPool</code> object.
-The second parameter of <code>onWrite()</code> is the name of the class
-to be written out.
-
-<p>Note that <code>start()</code> or <code>onWrite()</code> do not have
-to call <code>write()</code> or <code>writeFile()</code>. For example,
-
-<ul><pre>public class MyAnotherTranslator implements Translator {
- public void start(ClassPool pool)
- throws NotFoundException, CannotCompileException {}
- public void onWrite(ClassPool pool, String classname)
- throws NotFoundException, CannotCompileException
- {
- CtClass cc = pool.get(classname);
- cc.setModifiers(Modifier.PUBLIC);
- }
-}</pre></ul>
-
-<p>All the classes written out by <code>write()</code> are made public
-just before their definitions are translated into an byte array.
-
-<p><center><img src="overview.gif" alt="overview"></center>
-
-<p>The two methods <code>start()</code> and <code>onWrite()</code>
-can modify not only a <code>CtClass</code> object specified by
-the given <code>classname</code> but also
-<em>any</em> <code>CtClass</code> objects contained
-in the given <code>ClassPool</code>.
-They can call <code>ClassPool.get()</code> for obtaining any
-<code>CtClass</code> object.
-If a modified <code>CtClass</code> object is not written out immediately,
-the modification is recorded until that object is written out.
-
-<p><center><img src="sequence.gif" alt="sequence diagram"></center>
-
-<p>To register an event listener to a <code>ClassPool</code>,
-it must be passed to a constructor of <code>ClassPool</code>.
-Only a single event listener can be registered.
-If more than one event listeners are needed, multiple
-<code>ClassPool</code>s should be connected to be a single
-stream. For example,
-
-<ul><pre>Translator t1 = new MyTranslator();
-ClassPool c1 = new ClassPool(t1);
-Translator t2 = new MyAnotherTranslator();
-ClassPool c2 = new ClassPool(c1, t2);</pre></ul>
-
-<p>This program connects two <code>ClassPool</code>s.
-If a class loader calls <code>write()</code> on <code>c2</code>,
-the specified class file is first modified by <code>t1</code> and
-then by <code>t2</code>. <code>write()</code> returns the resulting
-class file.
-
-First, <code>onWrite()</code> on <code>t1</code> is called since
-<code>c2</code> obtains a class file by calling <code>write()</code>
-on <code>c1</code>. Then <code>onWrite()</code> on <code>t2</code>
-is called. If <code>onWrite()</code> called on <code>t2</code>
-obtains a <code>CtClass</code> object from <code>c2</code>, that
-<code>CtClass</code> object represents the class file that
-<code>t1</code> has modified.
-
-<p><center><img src="two.gif" alt="two translators"></center>
-
-<p><br>
-
-<a name="load">
-<h2>4. Class loader</h2>
-
-<p>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>
-
-<h3>4.1 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 into the JVM, and creates a new instance of the
-<code>test.Rectangle</code> class.
-
-<p>The users can use a <code>javassist.Translator</code> object
-for modifying class files.
-Suppose that an instance of a class <code>MyTranslator</code>,
-which implements
-<code>javassist.Translator</code>, performs modification of class files.
-To run an application class <code>MyApp</code> with the
-<code>MyTranslator</code> object, write a main class:
-
-<ul><pre>
-import javassist.*;
-
-public class Main2 {
- public static void main(String[] args) throws Throwable {
- Translator t = new MyTranslator();
- ClassPool pool = ClassPool.getDefault(t);
- Loader cl = new Loader(pool);
- cl.run("MyApp", args);
- }
-}
-</pre></ul>
-
-<p>To run this program, do:
-
-<ul><pre>
-% java Main <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>Main</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>Main</code> are by the default Java class loader.
-
-<p>In Java, for security reasons, a single class file may be loaded
-into the JVM by two distinct class loaders so that two different
-classes would be created. For example,
-
-<ul><pre>class Point {
- int x, y;
-}
-
-class Box {
- Point base;
- Point getBase() { return base; }
-}
-
-class Window {
- Point size;
- Point getSize() { return size; }
-}</pre></ul>
-
-<p>Suppose that a class <code>Box</code> is loaded by a class loader
-<code>L1</code> while a class <code>Window</code> is loaded by a class
-loader <code>L2</code>. Then, the obejcts returned by
-<code>getBase()</code> and <code>getSize()</code> are not instances of
-the same class <code>Point</code>.
-<code>getBase()</code> returns an instance of the class <code>Point</code>
-loaded by <code>L1</code> whereas <code>getSize()</code> returns an
-instance of <code>Point</code> loaded by <code>L2</code>. The two versions
-of the class <code>Point</code> are distinct. They belong to different
-name spaces. For more details, see the following paper:
-
-<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>To avoid this problem, the two class loaders <code>L1</code> and
-<code>L2</code> must delegate the loading operation of the class
-<code>Point</code> to another class loader, <code>L3</code>, which is
-a parent class loader of <code>L1</code> and <code>L2</code>.
-<code>delegateLoadingOf()</code> in <code>javassist.Loader</code>
-is a method for specifying what classes should be loaded by the
-parent loader.
-
-<p>If <code>L1</code> is the parent class loader of <code>L2</code>,
-that is, if <code>L1</code> loads the class of <code>L2</code>,
-then <code>L2</code> can delegate the loading operation of
-<code>Point</code> to <code>L1</code> for avoiding the problem above.
-However, this technique does not work in the case below:
-
-<ul><pre>class Point { // loaded by L1
- Window win;
- int x, y;
-}
-
-class Box { // loaded by L1
- Point base;
- Point getBase() { return base; }
-}
-
-class Window { // loaded by L2
- Point size;
- Point getSize() { size.win = this; return size; }
-}</pre></ul>
-
-<p>Since all the classes included in a class definition loaded by
-a class loader <code>L1</code> are also loaded by <code>L1</code>,
-the class of the field <code>win</code> in <code>Point</code> is
-now the class <code>Window</code> loaded by <code>L1</code>.
-Thus <code>size.win = this</code> in <code>getSize()</code> raises
-a runtime exception because of type mismatch; the type of
-<code>size.win</code> is the class <code>Point</code> loaded by
-<code>L1</code> whereas the type of <code>this</code> is the class
-<code>Point</code> loaded by <code>L2</code>.
-
-<p><br>
-
-<h3>4.2 Writing a class loader</h3>
-
-<p>A simple class loader using Javassist is as follows:
-
-<ul><pre>import javassist.*;
-
-public class SimpleLoader extends ClassLoader {
- /* Call MyApp.main().
- */
- public static void main(String[] args) throws Throwable {
- SimpleLoader s = new SimpleLoader();
- Class c = s.loadClass("MyApp");
- c.getDeclaredMethod("main", new Class[] { String[].class })
- .invoke(null, new Object[] { args });
- }
-
- private ClassPool pool;
-
- public SimpleLoader() throws NotFoundException {
- pool = ClassPool.getDefault();
- 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 = pool.write(name);
- 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. The directory name 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 SimpleLoader</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.
-Note that <code>MyApp.class</code> must not be under the directory
-that the system class loader searches. Otherwise, the system class
-loader, which is the parent loader of <code>SimpleLoader</code>,
-loads the class <code>MyApp</code>.
-
-<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>SimpleLoader</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>SimpleLoader</code>.
-
-<p><br>
-
-<h3>4.3 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>SimpleLoader</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");
-cc.addField(new CtField(CtClass.intType, "hiddenValue", cc));
-pool.writeFile("java.lang.String", ".");</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 href="tutorial2.html">Next page</a>
-
-<hr>
-Java(TM) is a trademark of Sun Microsystems, Inc.<br>
-Copyright (C) 2000-2002 by Shigeru Chiba, All rights reserved.
-</body>
-</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 bytecode</a>
+<br>2. <a href="#def">Defining a new class</a>
+<br>3. <a href="#mod">Modifying a class at load time</a>
+<br>4. <a href="#load">Class loader</a>
+<br>5. <a href="tutorial2.html#intro">Introspection and customization</a>
+</ul>
+
+<p><br>
+
+<a name="read">
+<h2>1. Reading 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> 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"));
+pool.writeFile("test.Rectangle"); // or simply, 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 contains the constructed object until it is written out
+to a file or an output stream.
+
+<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. This is a crucial feature to consistent program
+transformaiton.
+
+<p>To modify the definition of a class, the users must first obtain a
+reference to the <code>CtClass</code> object representing that class.
+<code>ClassPool.get()</code> is used for this purpose.
+In the case of the program 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>. Then 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>ClassPool.writeFile()</code> is finally called.
+
+<p>Note that <code>writeFile()</code> is a method declared in not
+<code>CtClass</code> but <code>ClassPool</code>.
+If this method is called, the <code>ClassPool</code>
+finds a <code>CtClass</code> object specified with a class name
+among the objects that the <code>ClassPool</code> contains.
+Then it translates that <code>CtClass</code> object into a class file
+and writes it on a local disk.
+
+<p>There is also <code>writeFile()</code> defined in <code>CtClass</code>.
+Thus, the last line in the program above can be rewritten into:
+
+<ul><pre>cc.writeFile();</pre></ul>
+
+<p>This method is a convenient method for invoking <code>writeFile()</code>
+in <code>ClassPool</code> with the name of the class represented by
+<code>cc</code>.
+
+<p>Javassist also provides a method for directly obtaining the
+modified bytecode. To do this, call <code>write()</code>:
+
+<ul><pre>
+byte[] b = pool.write("test.Rectangle");
+</pre></ul>
+
+<p>The contents of the class file for <code>test.Rectangle</code> are
+assigned to a variable <code>b</code> in the form of byte array.
+<code>writeFile()</code> also internally calls <code>write()</code>
+to obtain the byte array written in a class file.
+
+<p>The default <code>ClassPool</code> returned
+by a static method <code>ClassPool.getDefault()</code>
+searches the same path as the underlying JVM.
+The users can expand this class search path if needed.
+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.foo.com", 80, "/java/", "com.foo.");
+pool.insertClassPath(cp);
+</pre></ul>
+
+<p>This program adds "http://www.foo.com:80/java/" to the class search
+path. This URL is used only for searching classes belonging to a
+package <code>com.foo</code>.
+
+<p>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>.
+
+<p>Since <code>ClassPath</code> is an interface, the users can define
+a new class implementing this interface and they can add an instance
+of that class so that a class file is obtained from a non-standard resource.
+
+<p>If you want to directly construct a <code>CtClass</code> object
+from a class file but you do not know the fully-qualified name
+of the class, then
+you can use <code>makeClass()</code> in <code>CtClass</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
+the <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><br>
+
+<a name="def">
+<h2>2. Defining a new class</h2>
+
+<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.
+
+<p>A new class can be also defined as a copy of an existing class.
+The program below does that:
+
+<ul><pre>
+ClassPool pool = ClassPool.getDefault();
+CtClass cc = pool.makeClass("Point");
+cc.setName("Pair");
+</pre></ul>
+
+<p>This program first obtains the <code>CtClass</code> object
+for class <code>Point</code>. Then it gives a new name <code>Pair</code>
+to that <code>CtClass</code> object.
+If <code>get("Point")</code> is called on the <code>ClassPool</code>
+object, then a class file <code>Point.class</code> is read again and
+a new <code>CtClass</code> object for class <code>Point</code> is constructed
+again.
+
+<ul><pre>
+ClassPool pool = ClassPool.getDefault();
+CtClass cc = pool.makeClass("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><br>
+
+<a name="mod">
+<h2>3. Modifying a class at load time</h2>
+
+<p>If what classes are 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>ClassPool.write()</code> or <code>writeFile()</code>.
+</ul>
+
+<p>If whether a class is modified or not is determined at load time,
+the users can write an event listener so that it is notified
+when a class is loaded into the JVM.
+A class loader (<code>java.lang.ClassLoader</code>) working with
+Javassist must call <code>ClassPool.write()</code> for obtaining
+a class file. The users can write an event listener so that it is
+notified when the class loader calls <code>ClassPool.write()</code>.
+The event-listener class must implement the following interface:
+
+<ul><pre>public interface Translator {
+ public void start(ClassPool pool)
+ throws NotFoundException, CannotCompileException;
+ public void onWrite(ClassPool pool, String classname)
+ throws NotFoundException, CannotCompileException;
+}</pre></ul>
+
+<p>The method <code>start()</code> is called when this event listener
+is registered to a <code>ClassPool</code> object.
+The method <code>onWrite()</code> is called when <code>write()</code>
+(or similar methods) is called on the <code>ClassPool</code> object.
+The second parameter of <code>onWrite()</code> is the name of the class
+to be written out.
+
+<p>Note that <code>start()</code> or <code>onWrite()</code> do not have
+to call <code>write()</code> or <code>writeFile()</code>. For example,
+
+<ul><pre>public class MyAnotherTranslator implements Translator {
+ public void start(ClassPool pool)
+ throws NotFoundException, CannotCompileException {}
+ public void onWrite(ClassPool pool, String classname)
+ throws NotFoundException, CannotCompileException
+ {
+ CtClass cc = pool.get(classname);
+ cc.setModifiers(Modifier.PUBLIC);
+ }
+}</pre></ul>
+
+<p>All the classes written out by <code>write()</code> are made public
+just before their definitions are translated into an byte array.
+
+<p><center><img src="overview.gif" alt="overview"></center>
+
+<p>The two methods <code>start()</code> and <code>onWrite()</code>
+can modify not only a <code>CtClass</code> object specified by
+the given <code>classname</code> but also
+<em>any</em> <code>CtClass</code> objects contained
+in the given <code>ClassPool</code>.
+They can call <code>ClassPool.get()</code> for obtaining any
+<code>CtClass</code> object.
+If a modified <code>CtClass</code> object is not written out immediately,
+the modification is recorded until that object is written out.
+
+<p><center><img src="sequence.gif" alt="sequence diagram"></center>
+
+<p>To register an event listener to a <code>ClassPool</code>,
+it must be passed to a constructor of <code>ClassPool</code>.
+Only a single event listener can be registered.
+If more than one event listeners are needed, multiple
+<code>ClassPool</code>s should be connected to be a single
+stream. For example,
+
+<ul><pre>Translator t1 = new MyTranslator();
+ClassPool c1 = new ClassPool(t1);
+Translator t2 = new MyAnotherTranslator();
+ClassPool c2 = new ClassPool(c1, t2);</pre></ul>
+
+<p>This program connects two <code>ClassPool</code>s.
+If a class loader calls <code>write()</code> on <code>c2</code>,
+the specified class file is first modified by <code>t1</code> and
+then by <code>t2</code>. <code>write()</code> returns the resulting
+class file.
+
+First, <code>onWrite()</code> on <code>t1</code> is called since
+<code>c2</code> obtains a class file by calling <code>write()</code>
+on <code>c1</code>. Then <code>onWrite()</code> on <code>t2</code>
+is called. If <code>onWrite()</code> called on <code>t2</code>
+obtains a <code>CtClass</code> object from <code>c2</code>, that
+<code>CtClass</code> object represents the class file that
+<code>t1</code> has modified.
+
+<p><center><img src="two.gif" alt="two translators"></center>
+
+<p><br>
+
+<a name="load">
+<h2>4. Class loader</h2>
+
+<p>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>
+
+<h3>4.1 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 into the JVM, and creates a new instance of the
+<code>test.Rectangle</code> class.
+
+<p>The users can use a <code>javassist.Translator</code> object
+for modifying class files.
+Suppose that an instance of a class <code>MyTranslator</code>,
+which implements
+<code>javassist.Translator</code>, performs modification of class files.
+To run an application class <code>MyApp</code> with the
+<code>MyTranslator</code> object, write a main class:
+
+<ul><pre>
+import javassist.*;
+
+public class Main2 {
+ public static void main(String[] args) throws Throwable {
+ Translator t = new MyTranslator();
+ ClassPool pool = ClassPool.getDefault(t);
+ Loader cl = new Loader(pool);
+ cl.run("MyApp", args);
+ }
+}
+</pre></ul>
+
+<p>To run this program, do:
+
+<ul><pre>
+% java Main <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>Main</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>Main</code> are by the default Java class loader.
+
+<p>In Java, for security reasons, a single class file may be loaded
+into the JVM by two distinct class loaders so that two different
+classes would be created. For example,
+
+<ul><pre>class Point {
+ int x, y;
+}
+
+class Box {
+ Point base;
+ Point getBase() { return base; }
+}
+
+class Window {
+ Point size;
+ Point getSize() { return size; }
+}</pre></ul>
+
+<p>Suppose that a class <code>Box</code> is loaded by a class loader
+<code>L1</code> while a class <code>Window</code> is loaded by a class
+loader <code>L2</code>. Then, the obejcts returned by
+<code>getBase()</code> and <code>getSize()</code> are not instances of
+the same class <code>Point</code>.
+<code>getBase()</code> returns an instance of the class <code>Point</code>
+loaded by <code>L1</code> whereas <code>getSize()</code> returns an
+instance of <code>Point</code> loaded by <code>L2</code>. The two versions
+of the class <code>Point</code> are distinct. They belong to different
+name spaces. For more details, see the following paper:
+
+<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>To avoid this problem, the two class loaders <code>L1</code> and
+<code>L2</code> must delegate the loading operation of the class
+<code>Point</code> to another class loader, <code>L3</code>, which is
+a parent class loader of <code>L1</code> and <code>L2</code>.
+<code>delegateLoadingOf()</code> in <code>javassist.Loader</code>
+is a method for specifying what classes should be loaded by the
+parent loader.
+
+<p>If <code>L1</code> is the parent class loader of <code>L2</code>,
+that is, if <code>L1</code> loads the class of <code>L2</code>,
+then <code>L2</code> can delegate the loading operation of
+<code>Point</code> to <code>L1</code> for avoiding the problem above.
+However, this technique does not work in the case below:
+
+<ul><pre>class Point { // loaded by L1
+ Window win;
+ int x, y;
+}
+
+class Box { // loaded by L1
+ Point base;
+ Point getBase() { return base; }
+}
+
+class Window { // loaded by L2
+ Point size;
+ Point getSize() { size.win = this; return size; }
+}</pre></ul>
+
+<p>Since all the classes included in a class definition loaded by
+a class loader <code>L1</code> are also loaded by <code>L1</code>,
+the class of the field <code>win</code> in <code>Point</code> is
+now the class <code>Window</code> loaded by <code>L1</code>.
+Thus <code>size.win = this</code> in <code>getSize()</code> raises
+a runtime exception because of type mismatch; the type of
+<code>size.win</code> is the class <code>Point</code> loaded by
+<code>L1</code> whereas the type of <code>this</code> is the class
+<code>Point</code> loaded by <code>L2</code>.
+
+<p><br>
+
+<h3>4.2 Writing a class loader</h3>
+
+<p>A simple class loader using Javassist is as follows:
+
+<ul><pre>import javassist.*;
+
+public class SimpleLoader extends ClassLoader {
+ /* Call MyApp.main().
+ */
+ public static void main(String[] args) throws Throwable {
+ SimpleLoader s = new SimpleLoader();
+ Class c = s.loadClass("MyApp");
+ c.getDeclaredMethod("main", new Class[] { String[].class })
+ .invoke(null, new Object[] { args });
+ }
+
+ private ClassPool pool;
+
+ public SimpleLoader() throws NotFoundException {
+ pool = ClassPool.getDefault();
+ 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 = pool.write(name);
+ 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. The directory name 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 SimpleLoader</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.
+Note that <code>MyApp.class</code> must not be under the directory
+that the system class loader searches. Otherwise, the system class
+loader, which is the parent loader of <code>SimpleLoader</code>,
+loads the class <code>MyApp</code>.
+
+<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>SimpleLoader</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>SimpleLoader</code>.
+
+<p><br>
+
+<h3>4.3 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>SimpleLoader</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");
+cc.addField(new CtField(CtClass.intType, "hiddenValue", cc));
+pool.writeFile("java.lang.String", ".");</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 href="tutorial2.html">Next page</a>
+
+<hr>
+Java(TM) is a trademark of Sun Microsystems, Inc.<br>
+Copyright (C) 2000-2003 by Shigeru Chiba, All rights reserved.
+</body>
+</html>