| Sign In/My Account | View Cart |
Analyze Your Classes
Pages: 1, 2, 3
BCEL was formerly known as JavaClass. It was incorporated as an Apache Jakarta project in October 2001. The original JavaClass was written by Markus Dahm. The main site is hosted at jakarta.apache.org, from which you can access binaries and source code.
At the heart of BCEL is the JavaClass. A JavaClass represents a Java Class
file as described above, with all of the elements. There is a one-to-one mapping
between the elements of a Java class as described in the JVM specification and
the JavaClass. BCEL thus allows you to read a normal class file in your program
and treat it like any other object. The properties of this object are the Java
class file elements. Furthermore, a JavaClass, which has been created on the
fly within your program, represents an actual class file. If serialized, you
will be able to run this class file in a JVM, as you would do a normally compiled
source file.
BCEL allows you, at a micro level, to model the instructions contained within the Java class file. This way, you can navigate and manipulate this instruction set programmatically, allowing you to introduce enhancements and improvements in the runtime of your class. However, this is not the only way to introduce such enhancements. Better compilers and source code optimization can also do the same trick. Furthermore, it is easier to manipulate source code than it is to manipulate raw bytes. Having said all this, direct byte code manipulation has the advantage of being faster than any enhancement that you can do via compiler or source-code manipulation. This comes at the price of extra complexity. BCEL alleviates this complexity to a certain degree by allowing you to manipulate class files via source code.
Another feature of BCEL is what is called as load-time reflection. As opposed to run-time reflection, which is implemented by using the Reflection API built into the Java language, load-time reflection refers to the ability to modify the byte code instruction set at the time it is loaded. This involves writing a custom classloader, which instead of passing the byte code directly to the JVM, first passes it through your runtime system written using the BCEL API. Your system can then access meta-level objects created at load time and manipulate them. This process can even create these objects without source code present. The result continues normally after this where it is passed to the byte code verifier and then executed in the JVM.
The BCEL API is roughly divided into two parts:
Static API
This is the part of the API that deals with mapping the data
structures and binary components described in the JVM specification. You would
use this part if you were analyzing existing classes without access to the
source code.
The main class in this part is called JavaClass, which represents
a Java class and includes all the data structures, constant pool, fields,
methods, and commands contained in a class file. It supports the Visitor
design pattern, which allows developers to write their own visitor code
to traverse and analyze the contents of a class file. The JavaClass
itself derives from AccessFlags class, which is the class that
is extended by all classes that have access flags. This thus applies to
not only JavaClass, but also to the FieldOrMethod class,
the super class for Field and Method as well.
The Constant Pool is represented by the ConstantPool class.
It contains an array of type Constant that represents the
different constant types in the constant pool of a parsed class file. For
example, it may contain ConstantInteger, which represents reference
to an int object. You can access the constants using an index and by calling
the method getConstant(int index). Note that this internal
array may contain a null reference. This happens in the case of
double or long references that,
per the JVM specification, require a skip after an entry.
Another interesting class in the API is the Repository class.
This class is used to read existing class files into the system and for
resolving class interdependencies.
Generic API
This part of the API deals with creating or transforming class
files dynamically. It allows you to create a class file from scratch or read
an existing class file and dynamically modify it.
The central class in this API is the ClassGen class. This
class allows you to create a new class file and to add methods, attributes
and fields to it dynamically. You can load an existing class file in by
passing in a JavaClass that represents a file loaded into
memory as described in the Static API. This class also contains methods
to search this class for particular methods and fields, to replace existing
methods and fields, and remove existing methods and fields. You can also directly
use the MethodsGen and the FieldsGen classes for
generating methods and fields, respectively.
Corresponding to the ClassGen class is the ConstantPoolGen
class. This class allows you to add different types of constants and retrieve
the ConstantPool once you are done adding the constants by calling
getFinalConstantPool(). Constants are added using methods like addString(String str),
addInteger(int n), etc. These methods return the index at which
the constant was added. If you are not done adding constants to the pool
and yet want to access the ConstantPool in the state that it is in, you can
call getConstantPool(). This class also allows you to look up
existing entries in the pool with corresponding lookupString(String
str) and lookupInteger(int n) methods.
The BCEL API contains a stack of utility classes that allow you to get started
with the API without worrying too much about the semantics or getting involved
in the complexities. These include Class2HTML, a utility to transform class
files into HTML, JavaWrapper, a utility that acts as a wrapper to modify and
generate classes as they are requested using its own class loader, and BCELifier,
which takes a JavaClass object and generates BCEL Java source code to build
that class.
The following examples start with the utility classes and follow up with simple examples of using the static and dynamic API.
|
Source Code Download the source code for the examples. |
Important: Make sure that before you run these examples, you have set the CLASSPATH to include bcel.jar.
The easiest way to start with BCEL is to use the BCELifier, because
it generates the BCEL source code used to generate the class file itself and
is a very handy way of learning how BCEL works. It generates the code that
you would have to write yourself if you were to write the BCEL code for generating
the class file dynamically.
The following is a simple HelloWorld source file that I will use for this
example.
public class HelloWorld{
public static void main(String args[]){
System.err.println("Hello World through BCEL!");
}
}
Compile this class and produce the HelloWorld.class file.
Next, run the following command (all on one line) in the directory where you compiled HelloWorld.class:
java org.apache.bcel.util.BCELifier
HelloWorld.class >> HelloWorldCreator.java
Because the BCELifier class outputs the result to standard out, I have
piped the output to the resulting source file. Note that BCELifier creates
the source file as "ClassFileName" + "Creator". Hence, the BCELified
HelloWorld.class gets named HelloWorldCreator.java.
Compile and run HelloWorldCreator.java. You will see the output on the console as: "Hello World through BCEL!".
Open HelloWorldCreator.java and examine it. You will see that creating such a simple class is quite a complex process, even through BCEL abstracts most of the functionality of the Java class file.