Package edu.rit.classfile is the RIT Classfile Library for analyzing and synthesizing class files. (Analysis capabilities are not yet implemented.)

Section 1 gives an overview of the RIT Classfile Library. Section 2 discusses why I chose to develop yet another Java library for manipulating class files. Section 3 describes how to synthesize a class. Section 4 describes how to synthesize an interface. Section 5 describes how to load synthesized class files into the Java Virtual Machine (JVM).


Table of Contents

1. Overview
2. An Apology
3. Synthesizing a Class
4. Synthesizing an Interface
5. Loading Synthesized Classes
6. References
7. License
8. Revision History


1. Overview

With the RIT Classfile Library you can analyze an existing class file to discover which class, fields, methods, and so on it contains. While you can get the same information using the Java Reflection API (package java.lang.reflect), the Java Reflection API first requires you to load the class into the JVM. The RIT Classfile Library can analyze a class file without actually loading the class. Also, since it doesn’t use reflection, the RIT Classfile Library can be used in Java environments that lack reflection, such as the Java 2 Micro Edition Connected Limited Device Configuration (J2ME CLDC).

Note: The RIT Classfile Library’s analysis capabilities are not yet implemented and will appear in a future version of the Library.

With the RIT Classfile Library you can also synthesize a new class file and load it directly into the JVM. In this way, a running program can create a new class without having to generate a source file and run the Java compiler. Thus, the RIT Classfile Library can be used to create new classes in Java environments that lack a Java compiler and/or a file system, such as the J2ME CLDC.

The original motivation for writing the RIT Classfile Library was to enable the development of remote method invocation systems that generate their own stubs automatically rather than relying on a human to run an offline stub compiler. Java’s dynamic proxies (class java.lang.reflect.Proxy) provide a similar capability. However, custom-synthesized stub classes generally execute more quickly than dynamic proxies that use reflection, and hence are more attractive in applications where performance is a concern. Also, the RIT Classfile Library is fully general and can synthesize any class, not just a proxy for an interface.


2. An Apology

apology 1 a : a formal justification : DEFENSE
Webster’s New Collegiate Dictionary

I’m aware of half a dozen or so programs and APIs with capabilities similar to those of the RIT Classfile Library. Why write another one? Does the world need yet another library for manipulating Java class files?

I wrote the RIT Classfile Library because I wasn’t satisfied with the existing programs and libraries for my purpose, synthesizing remote method invocation stubs in small devices with limited (J2ME CLDC) Java environments. Some programs are class file “assemblers” that take their input from a source file; this won’t work in a small device with no file system, and the code for parsing source text, generating error messages, and so on is unnecessary overhead for my purpose. Some libraries are over-general, with beautifully object-oriented designs but quite large and complex class hierarchies; the code footprint of such libraries is problematic for small devices with limited memories. Some libraries tangle analysis and synthesis capabilities together in the same classes, so that it’s difficult to subset the library to do just one or the other; again, this leads to a larger than necessary code footprint. Some libraries expose the low-level details of the Java class file data structures like the “constant pool” and the “code attributes;” I find a high-level API that hides these details easier to work with.

My goals in writing the RIT Classfile Library were


3. Synthesizing a Class

I assume you’re familiar with JVM internals. See the References for further information.

To synthesize a class, first create an instance of class SynthesizedClassDescription. A class description is an object that holds information about everything that’s in a class. A synthesized class description is a class description where you fill out (synthesize) the class information yourself. (The other kind of class description, an analyzed class description, is a class description where the class information comes from a pre-existing class file. Analysis capabilities are not yet implemented in the RIT Classfile Library.)

Once you have the synthesized class description object, populate it with fields, methods, and whatever other information the class needs. Next, tell the synthesized class description object to emit its binary class file into an output stream, such as a FileOutputStream or a ByteArrayOutputStream. Finally, to use your new class, load it into the JVM as described later.

When synthesizing your class, you’ll need to refer to other classes and types — for example, to specify the superclass of your class, or to specify the data type for a field in your class. A type reference is an object that holds just enough information to refer to some data type. You can use any of several kinds of type reference:

To add a field to your class, create a field description object, which holds all information about the field. You can use any of several kinds of field description:

To add a subroutine to your class, create a subroutine description object, which holds all information about the subroutine. The term “subroutine” refers collectively to constructors, methods, and class initializers. You can use any of several kinds of subroutine description:

Each subroutine (except an abstract method) needs a sequence of bytecode instructions. You use class Op to obtain each instruction, then you add each instruction to the subroutine description. You can also add instances of class Location to mark the target locations for branch instructions.

Some bytecode instructions refer to fields or methods that exist elsewhere. To refer to a field, use a field reference object. Class NamedFieldReference lets you refer to a field by name. A field description can also be used as a field reference.

To refer to a subroutine, use a subroutine reference object. You can use any of several kinds of subroutine reference:

There are two very important pieces of information you must specify for each subroutine (except an abstract method): max_stack, which gives the maximum number of words the subroutine ever pushes on the operand stack, and max_locals, which gives the number of words needed to hold the subroutine’s this pointer, arguments, and local variables. If you don’t specify the correct max_stack and max_locals, your class may fail verification when loaded, or your subroutine may behave incorrectly when invoked.


4. Synthesizing an Interface

To synthesize an interface, first create an instance of class SynthesizedInterfaceDescription. An interface description is an object that holds information about everything that’s in an interface. A synthesized interface description is an interface description where you fill out (synthesize) the interface information yourself. (The other kind of interface description, an analyzed interface description, is an interface description where the interface information comes from a pre-existing class file. Analysis capabilities are not yet implemented in the RIT class file Library.)

Once you have the synthesized interface description object, you work with it in exactly the same way as a synthesized class description object. Populate it with fields, methods, and whatever other information the interface needs. Next, tell the synthesized interface description object to emit its binary class file into an output stream, such as a FileOutputStream or a ByteArrayOutputStream. Finally, to use your new interface, load it into the JVM as described later.

The only fields you can have in an interface are public static final fields. To add such a field to your interface, create a field description object that is an instance of class SynthesizedInterfaceFieldDescription.

The only methods you can have in an interface are public abstract methods. To add such a method to your interface, create a subroutine description object that is an instance of class SynthesizedInterfaceMethodDescription. An interface can also have a class initializer (class SynthesizedClassInitializerDescription) to initialize the interface’s fields if necessary.


5. Loading Synthesized Classes

After you’ve filled everything out, a synthesized class description object lets you emit the binary class file into an output stream. (Everything in this section applies to synthesized interfaces too. For brevity, I’ll omit mentioning interfaces.) To create actual instances of the synthesized class, you have to load this class file into the JVM. Two strategies are possible.

You can store the binary class file in a file (using a FileOutputStream), placing the file where a class loader can find it. For example, you can place the file in the proper directory in the system class loader’s CLASSPATH. Or you can place the file in any old directory, and use a URLClassLoader to get the file from the proper "file://" URL. Or you can place the file where an HTTP server can retrieve it, and use a URLClassLoader to get the file from the proper "http://" URL.

Alternatively, you can feed the binary class file directly into a class loader, bypassing the file system altogether. The RIT Classfile Library provides a special class loader implementation for this purpose, class DirectClassLoader. To feed a class file into a direct class loader, you obtain an output stream from the direct class loader and emit the synthesized class file into this output stream. When later told to load that class, the direct class loader gets the class file from the bytes that were written.


6. References

  1. Tim Lindholm and Frank Yellin. The Java™ Virtual Machine Specification, 2nd Edition. Reading, MA: Addison-Wesley, 1999. http://java.sun.com/docs/books/vmspec/2nd-edition/html/VMSpecTOC.doc.html

  2. Bill Venners. Inside the Java Virtual Machine, 2nd Edition. New York, NY: McGraw-Hill, 1999.


7. License

The documentation and Java source files in the RIT Classfile Library ("The Library") are copyright © 2001, 2002 by the Rochester Institute of Technology. All rights reserved. For further information, contact the author, Alan Kaminsky, at ark@it.rit.edu.

The Library is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

The Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

A copy of the GNU General Public License is provided in the file gpl.txt. You may also obtain a copy of the GNU General Public License on the World Wide Web at http://www.gnu.org/licenses/gpl.html or by writing to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.


8. Revision History

22-Aug-2003
No changes to functionality. Bumped the date to stay in sync with the M2MI Library and the M2MP Library.

02-Jul-2002
No changes to functionality. Bumped the date to stay in sync with the M2MI Library and the M2MP Library.

07-Jun-2002
Added a few classes and methods needed by the Many-to-Many Invocation (M2MI) Library. Released under the terms of the GNU General Public License (no longer the GNU Lesser General Public License).

12-Oct-2001
Initial version. Includes the classfile synthesis capability and test programs. Released under the terms of the GNU Lesser General Public License.