ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Analyze Your Classes
Pages: 1, 2, 3

BCEL Basics

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.

BCEL API

The BCEL API is roughly divided into two parts:

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

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

Examples

Important: Make sure that before you run these examples, you have set the CLASSPATH to include bcel.jar.

BCELifier

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.

Pages: 1, 2, 3

Next Pagearrow