From cdeddfd6fc34a06734f9fa525cf5c7437a6c8fb6 Mon Sep 17 00:00:00 2001 From: chiba Date: Wed, 23 Apr 2003 17:08:37 +0000 Subject: Changed the copyright notices and removed tab characters. git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@9 30ef5769-5b8d-40dd-aea6-55b5d6557bb3 --- tutorial/tutorial.html | 1148 +++++++++++++++++++++++++----------------------- 1 file changed, 588 insertions(+), 560 deletions(-) (limited to 'tutorial/tutorial.html') 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 @@ - - - - Javassist Tutorial - - - - - - -Getting Started with Javassist - - -

-Shigeru Chiba - - - -

Next page
- - - -


- - -

1. Reading bytecode

- -

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. - -

The class Javassist.CtClass is an abstract representation -of a class file. A CtClass object is a handle for dealing -with a class file. The following program is a very simple example: - -

- -

This program first obtains a ClassPool object, -which controls bytecode modification with Javassist. -The ClassPool object is a container of CtClass -object representing a class file. -It reads a class file on demand for constructing a CtClass -object and contains the constructed object until it is written out -to a file or an output stream. - -

To modify the definition of a class, the users must first obtain a -reference to the CtClass object representing that class. -ClassPool.get() is used for this purpose. -In the case of the program above, the CtClass object -representing a class test.Rectangle is obtained from -the ClassPool object -and it is assigned -to a variable cc. Then it is modified so that -the superclass of test.Rectangle is changed into -a class test.Point. -This change is reflected on the original class file when -ClassPool.writeFile() is finally called. - -

Note that writeFile() is a method declared in not -CtClass but ClassPool. -If this method is called, the ClassPool -finds a CtClass object specified with a class name -among the objects that the ClassPool contains. -Then it translates that CtClass object into a class file -and writes it on a local disk. - -

There is also writeFile() defined in CtClass. -Thus, the last line in the program above can be rewritten into: - -

- -

This method is a convenient method for invoking writeFile() -in ClassPool with the name of the class represented by -cc. - -

Javassist also provides a method for directly obtaining the -modified bytecode. To do this, call write(): - -

- -

The contents of the class file for test.Rectangle are -assigned to a variable b in the form of byte array. -writeFile() also internally calls write() -to obtain the byte array written in a class file. - -

The default ClassPool returned -by a static method ClassPool.getDefault() -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 -/usr/local/javalib -to the search path: - -

- -

The search path that the users can add is not only a directory but also -a URL: - -

- -

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 com.foo. - -

You can directly give a byte array to a ClassPool object -and construct a CtClass object from that array. To do this, -use ByteArrayClassPath. For example, - -

- -

The obtained CtClass object represents -a class defined by the class file specified by b. - - -

Since ClassPath 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. - -


- -
-

2. Defining a new class

- -

To define a new class from scratch, makeClass() -must be called on a ClassPool. - -

- -

This program defines a class Point -including no members. - -

A new class can be also defined as a copy of an existing class. -The program below does that: - -

- -

This program first obtains the CtClass object -for class Point. Then it gives a new name Pair -to that CtClass object. -If get("Point") is called on the ClassPool -object, then a class file Point.class is read again and -a new CtClass object for class Point is constructed -again. - -

- -


- -
-

3. Modifying a class at load time

- -

If what classes are modified is known in advance, -the easiest way for modifying the classes is as follows: - -

- -

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 (java.lang.ClassLoader) working with -Javassist must call ClassPool.write() for obtaining -a class file. The users can write an event listener so that it is -notified when the class loader calls ClassPool.write(). -The event-listener class must implement the following interface: - -

- -

The method start() is called when this event listener -is registered to a ClassPool object. -The method onWrite() is called when write() -(or similar methods) is called on the ClassPool object. -The second parameter of onWrite() is the name of the class -to be written out. - -

Note that start() or onWrite() do not have -to call write() or writeFile(). For example, - -

- -

All the classes written out by write() are made public -just before their definitions are translated into an byte array. - -

overview
- -

The two methods start() and onWrite() -can modify not only a CtClass object specified by -the given classname but also -any CtClass objects contained -in the given ClassPool. -They can call ClassPool.get() for obtaining any -CtClass object. -If a modified CtClass object is not written out immediately, -the modification is recorded until that object is written out. - -

sequence diagram
- -

To register an event listener to a ClassPool, -it must be passed to a constructor of ClassPool. -Only a single event listener can be registered. -If more than one event listeners are needed, multiple -ClassPools should be connected to be a single -stream. For example, - -

- -

This program connects two ClassPools. -If a class loader calls write() on c2, -the specified class file is first modified by t1 and -then by t2. write() returns the resulting -class file. - -First, onWrite() on t1 is called since -c2 obtains a class file by calling write() -on c1. Then onWrite() on t2 -is called. If onWrite() called on t2 -obtains a CtClass object from c2, that -CtClass object represents the class file that -t1 has modified. - -

two translators
- -


- -
-

4. 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. - -


- -

4.1 Using javassist.Loader

- -

Javassist provides a class loader -javassist.Loader. This class loader uses a -javassist.ClassPool object for reading a class file. - -

For example, javassist.Loader can be used for loading -a particular class modified with Javassist. - -

- -

This program modifies a class test.Rectangle. The -superclass of test.Rectangle is set to a -test.Point class. Then this program loads the modified -class into the JVM, and creates a new instance of the -test.Rectangle class. - -

The users can use a javassist.Translator object -for modifying class files. -Suppose that an instance of a class MyTranslator, -which implements -javassist.Translator, performs modification of class files. -To run an application class MyApp with the -MyTranslator object, write a main class: - -

- -

To run this program, do: - -

- -

The class MyApp and the other application classes -are translated by MyTranslator. - -

Note that application classes like MyApp cannot -access the loader classes such as Main, -MyTranslator and ClassPool because they -are loaded by different loaders. The application classes are loaded -by javassist.Loader whereas the loader classes such as -Main are by the default Java class loader. - -

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, - -

- -

Suppose that a class Box is loaded by a class loader -L1 while a class Window is loaded by a class -loader L2. Then, the obejcts returned by -getBase() and getSize() are not instances of -the same class Point. -getBase() returns an instance of the class Point -loaded by L1 whereas getSize() returns an -instance of Point loaded by L2. The two versions -of the class Point are distinct. They belong to different -name spaces. For more details, see the following paper: - -

- -

To avoid this problem, the two class loaders L1 and -L2 must delegate the loading operation of the class -Point to another class loader, L3, which is -a parent class loader of L1 and L2. -delegateLoadingOf() in javassist.Loader -is a method for specifying what classes should be loaded by the -parent loader. - -

If L1 is the parent class loader of L2, -that is, if L1 loads the class of L2, -then L2 can delegate the loading operation of -Point to L1 for avoiding the problem above. -However, this technique does not work in the case below: - -

- -

Since all the classes included in a class definition loaded by -a class loader L1 are also loaded by L1, -the class of the field win in Point is -now the class Window loaded by L1. -Thus size.win = this in getSize() raises -a runtime exception because of type mismatch; the type of -size.win is the class Point loaded by -L1 whereas the type of this is the class -Point loaded by L2. - -


- -

4.2 Writing a class loader

- -

A simple class loader using Javassist is as follows: - -

- -

The class MyApp is an application program. -To execute this program, first put the class file under the -./class directory, which must not be included -in the class search path. The directory name is specified by -insertClassPath() in the constructor. -You can choose a different name instead of ./class if you want. -Then do as follows: - -

- -

The class loader loads the class MyApp -(./class/MyApp.class) and calls -MyApp.main() with the command line parameters. -Note that MyApp.class must not be under the directory -that the system class loader searches. Otherwise, the system class -loader, which is the parent loader of SimpleLoader, -loads the class MyApp. - -

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 -MyApp class in a name space separated from the name space -that the class SimpleLoader belongs to because the two -classes are loaded by different class loaders. -Hence, the -MyApp class cannot directly access the class -SimpleLoader. - -


- -

4.3 Modifying a system class

- -

The system classes like java.lang.String cannot be -loaded by a class loader other than the system class loader. -Therefore, SimpleLoader or javassist.Loader -shown above cannot modify the system classes at loading time. - -

If your application needs to do that, the system classes must be -statically modified. For example, the following program -adds a new field hiddenValue to java.lang.String: - -

- -

This program produces a file "./java/lang/String.class". - -

To run your program MyApp -with this modified String class, do as follows: - -

- -

Suppose that the definition of MyApp is as follows: - -

- -

If the modified String class is correctly loaded, -MyApp prints hiddenValue. - -

Note: Applications that use this technique for the purpose of -overriding a system class in rt.jar should not be -deployed as doing so would contravene the Java 2 Runtime Environment -binary code license. - -


- -
Next page - -


-Java(TM) is a trademark of Sun Microsystems, Inc.
-Copyright (C) 2000-2002 by Shigeru Chiba, All rights reserved. - - + + + + Javassist Tutorial + + + + + + +Getting Started with Javassist + + +

+Shigeru Chiba + + + +

Next page
+ + + +


+ + +

1. Reading bytecode

+ +

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. + +

The class Javassist.CtClass is an abstract representation +of a class file. A CtClass object is a handle for dealing +with a class file. The following program is a very simple example: + +

+ +

This program first obtains a ClassPool object, +which controls bytecode modification with Javassist. +The ClassPool object is a container of CtClass +object representing a class file. +It reads a class file on demand for constructing a CtClass +object and contains the constructed object until it is written out +to a file or an output stream. + +

The ClassPool object is used to maintain one-to-one +mapping between classes and CtClass objects. Javassist +never allows two distinct CtClass objects to represent +the same class. This is a crucial feature to consistent program +transformaiton. + +

To modify the definition of a class, the users must first obtain a +reference to the CtClass object representing that class. +ClassPool.get() is used for this purpose. +In the case of the program above, the CtClass object +representing a class test.Rectangle is obtained from +the ClassPool object +and it is assigned +to a variable cc. Then it is modified so that +the superclass of test.Rectangle is changed into +a class test.Point. +This change is reflected on the original class file when +ClassPool.writeFile() is finally called. + +

Note that writeFile() is a method declared in not +CtClass but ClassPool. +If this method is called, the ClassPool +finds a CtClass object specified with a class name +among the objects that the ClassPool contains. +Then it translates that CtClass object into a class file +and writes it on a local disk. + +

There is also writeFile() defined in CtClass. +Thus, the last line in the program above can be rewritten into: + +

+ +

This method is a convenient method for invoking writeFile() +in ClassPool with the name of the class represented by +cc. + +

Javassist also provides a method for directly obtaining the +modified bytecode. To do this, call write(): + +

+ +

The contents of the class file for test.Rectangle are +assigned to a variable b in the form of byte array. +writeFile() also internally calls write() +to obtain the byte array written in a class file. + +

The default ClassPool returned +by a static method ClassPool.getDefault() +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 +/usr/local/javalib +to the search path: + +

+ +

The search path that the users can add is not only a directory but also +a URL: + +

+ +

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 com.foo. + +

You can directly give a byte array to a ClassPool object +and construct a CtClass object from that array. To do this, +use ByteArrayClassPath. For example, + +

+ +

The obtained CtClass object represents +a class defined by the class file specified by b. + +

Since ClassPath 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. + +

If you want to directly construct a CtClass object +from a class file but you do not know the fully-qualified name +of the class, then +you can use makeClass() in CtClass: + +

+ +

makeClass() returns the CtClass object +constructed from the given input stream. You can use +makeClass() for eagerly feeding class files to +the ClassPool object. This might improve performance +if the search path includes a large jar file. Since +the ClassPool object reads a class file on demand, +it might repeatedly search the whole jar file for every class file. +makeClass() can be used for optimizing this search. +The CtClass constructed by makeClass() +is kept in the ClassPool object and the class file is never +read again. + +


+ +
+

2. Defining a new class

+ +

To define a new class from scratch, makeClass() +must be called on a ClassPool. + +

+ +

This program defines a class Point +including no members. + +

A new class can be also defined as a copy of an existing class. +The program below does that: + +

+ +

This program first obtains the CtClass object +for class Point. Then it gives a new name Pair +to that CtClass object. +If get("Point") is called on the ClassPool +object, then a class file Point.class is read again and +a new CtClass object for class Point is constructed +again. + +

+ +


+ +
+

3. Modifying a class at load time

+ +

If what classes are modified is known in advance, +the easiest way for modifying the classes is as follows: + +

+ +

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 (java.lang.ClassLoader) working with +Javassist must call ClassPool.write() for obtaining +a class file. The users can write an event listener so that it is +notified when the class loader calls ClassPool.write(). +The event-listener class must implement the following interface: + +

+ +

The method start() is called when this event listener +is registered to a ClassPool object. +The method onWrite() is called when write() +(or similar methods) is called on the ClassPool object. +The second parameter of onWrite() is the name of the class +to be written out. + +

Note that start() or onWrite() do not have +to call write() or writeFile(). For example, + +

+ +

All the classes written out by write() are made public +just before their definitions are translated into an byte array. + +

overview
+ +

The two methods start() and onWrite() +can modify not only a CtClass object specified by +the given classname but also +any CtClass objects contained +in the given ClassPool. +They can call ClassPool.get() for obtaining any +CtClass object. +If a modified CtClass object is not written out immediately, +the modification is recorded until that object is written out. + +

sequence diagram
+ +

To register an event listener to a ClassPool, +it must be passed to a constructor of ClassPool. +Only a single event listener can be registered. +If more than one event listeners are needed, multiple +ClassPools should be connected to be a single +stream. For example, + +

+ +

This program connects two ClassPools. +If a class loader calls write() on c2, +the specified class file is first modified by t1 and +then by t2. write() returns the resulting +class file. + +First, onWrite() on t1 is called since +c2 obtains a class file by calling write() +on c1. Then onWrite() on t2 +is called. If onWrite() called on t2 +obtains a CtClass object from c2, that +CtClass object represents the class file that +t1 has modified. + +

two translators
+ +


+ +
+

4. 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. + +


+ +

4.1 Using javassist.Loader

+ +

Javassist provides a class loader +javassist.Loader. This class loader uses a +javassist.ClassPool object for reading a class file. + +

For example, javassist.Loader can be used for loading +a particular class modified with Javassist. + +

+ +

This program modifies a class test.Rectangle. The +superclass of test.Rectangle is set to a +test.Point class. Then this program loads the modified +class into the JVM, and creates a new instance of the +test.Rectangle class. + +

The users can use a javassist.Translator object +for modifying class files. +Suppose that an instance of a class MyTranslator, +which implements +javassist.Translator, performs modification of class files. +To run an application class MyApp with the +MyTranslator object, write a main class: + +

+ +

To run this program, do: + +

+ +

The class MyApp and the other application classes +are translated by MyTranslator. + +

Note that application classes like MyApp cannot +access the loader classes such as Main, +MyTranslator and ClassPool because they +are loaded by different loaders. The application classes are loaded +by javassist.Loader whereas the loader classes such as +Main are by the default Java class loader. + +

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, + +

+ +

Suppose that a class Box is loaded by a class loader +L1 while a class Window is loaded by a class +loader L2. Then, the obejcts returned by +getBase() and getSize() are not instances of +the same class Point. +getBase() returns an instance of the class Point +loaded by L1 whereas getSize() returns an +instance of Point loaded by L2. The two versions +of the class Point are distinct. They belong to different +name spaces. For more details, see the following paper: + +

+ +

To avoid this problem, the two class loaders L1 and +L2 must delegate the loading operation of the class +Point to another class loader, L3, which is +a parent class loader of L1 and L2. +delegateLoadingOf() in javassist.Loader +is a method for specifying what classes should be loaded by the +parent loader. + +

If L1 is the parent class loader of L2, +that is, if L1 loads the class of L2, +then L2 can delegate the loading operation of +Point to L1 for avoiding the problem above. +However, this technique does not work in the case below: + +

+ +

Since all the classes included in a class definition loaded by +a class loader L1 are also loaded by L1, +the class of the field win in Point is +now the class Window loaded by L1. +Thus size.win = this in getSize() raises +a runtime exception because of type mismatch; the type of +size.win is the class Point loaded by +L1 whereas the type of this is the class +Point loaded by L2. + +


+ +

4.2 Writing a class loader

+ +

A simple class loader using Javassist is as follows: + +

+ +

The class MyApp is an application program. +To execute this program, first put the class file under the +./class directory, which must not be included +in the class search path. The directory name is specified by +insertClassPath() in the constructor. +You can choose a different name instead of ./class if you want. +Then do as follows: + +

+ +

The class loader loads the class MyApp +(./class/MyApp.class) and calls +MyApp.main() with the command line parameters. +Note that MyApp.class must not be under the directory +that the system class loader searches. Otherwise, the system class +loader, which is the parent loader of SimpleLoader, +loads the class MyApp. + +

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 +MyApp class in a name space separated from the name space +that the class SimpleLoader belongs to because the two +classes are loaded by different class loaders. +Hence, the +MyApp class cannot directly access the class +SimpleLoader. + +


+ +

4.3 Modifying a system class

+ +

The system classes like java.lang.String cannot be +loaded by a class loader other than the system class loader. +Therefore, SimpleLoader or javassist.Loader +shown above cannot modify the system classes at loading time. + +

If your application needs to do that, the system classes must be +statically modified. For example, the following program +adds a new field hiddenValue to java.lang.String: + +

+ +

This program produces a file "./java/lang/String.class". + +

To run your program MyApp +with this modified String class, do as follows: + +

+ +

Suppose that the definition of MyApp is as follows: + +

+ +

If the modified String class is correctly loaded, +MyApp prints hiddenValue. + +

Note: Applications that use this technique for the purpose of +overriding a system class in rt.jar should not be +deployed as doing so would contravene the Java 2 Runtime Environment +binary code license. + +


+ +
Next page + +


+Java(TM) is a trademark of Sun Microsystems, Inc.
+Copyright (C) 2000-2003 by Shigeru Chiba, All rights reserved. + + -- cgit v1.2.3