Skip to content
Home » Apache Commons BCEL: Getting Started

Apache Commons BCEL: Getting Started

The Apache Commons Byte Code Engineering Library (BCEL) is a powerful tool for the analysis, creation, and manipulation of Java class files. It provides Java developers with an API that enables the inspection of class files, bytecode creation, and even on-the-fly class file modification.

BCEL is part of the larger Apache Commons project, which is a library of useful, reusable Java components. Each component in Apache Commons is a standalone project with its own development team and release cycle.

Before we delve into examples of the most common and widely used functions, let’s take a moment to understand the core concepts and components of BCEL.

Core Concepts and Components

JavaClass and Method

JavaClass and Method are two of the most fundamental classes in BCEL. JavaClass instances represent a Java class file. This class provides methods to inspect the class file’s fields, methods, constants, etc. Method, on the other hand, represents a method in a Java class. It provides methods to inspect the method’s name, signature, bytecode, etc.

ConstantPool

ConstantPool is another fundamental class in BCEL. A constant pool is a collection of constants that a Java class or interface uses. This could be anything from class and method names to string constants and numeric values. BCEL’s ConstantPool class allows you to inspect and manipulate these constants.

InstructionFactory and InstructionList

InstructionFactory and InstructionList are key to bytecode manipulation in BCEL. InstructionFactory is used to create instances of Instruction, which represent JVM bytecode instructions. InstructionList is a container for these instructions. It provides methods for adding, removing, and manipulating instructions.

Apache Commons BCEL – Some Examples

Now let’s look at some examples of how to use BCEL. For the examples, we will assume the necessary BCEL classes have been imported and an instance of SyntheticRepository has been created. SyntheticRepository is a class in BCEL that provides a means to load JavaClass objects.

Loading a Class File

The first step in working with BCEL is usually to load a Java class file. This can be done using the loadClass method of SyntheticRepository.

SyntheticRepository repository = SyntheticRepository.getInstance(new ClassPath("."));
JavaClass javaClass = repository.loadClass("MyClass");
Java

In this example, a JavaClass object representing the class MyClass is loaded from the current classpath.

Inspecting a Class File

Once a JavaClass object is loaded, you can use it to inspect various aspects of the class file. For example, to print out the names and signatures of all methods in the class, you can do:

Method[] methods = javaClass.getMethods();
for (Method method : methods) {
    System.out.println("Method name: " + method.getName());
    System.out.println("Method signature: " + method.getSignature());
}
Java

Creating a New Method

BCEL also allows you to create new methods in a class. The InstructionFactory and InstructionList classes are used for this purpose.

// Create a new method
InstructionList il = new InstructionList();
il.append(InstructionFactory.createReturn(Type.VOID));
MethodGen methodGen = new MethodGen(ACC_PUBLIC | ACC_STATIC, // access flags
                                    Type.VOID,   // return type
                                    null,   // argument types
                                    null,   // arg names
                                    "newMethod", // method name
                                    "MyClass", // class name
                                    il,
                                    javaClass.getConstant

Pool());
// Add the method to the class
javaClass.addMethod(methodGen.getMethod());
Java

In this example, a new method named newMethod is created. This method takes no arguments and returns void. The method’s body contains just a single instruction: a return instruction. This method is then added to the class MyClass.

Modifying Existing Methods

BCEL can also be used to modify existing methods. For example, to add a print statement to the beginning of a method, you could do:

Method method = javaClass.getMethod("someMethod");
MethodGen methodGen = new MethodGen(method, javaClass.getClassName(), javaClass.getConstantPool());

InstructionFactory factory = new InstructionFactory(javaClass);
InstructionList instructions = methodGen.getInstructionList();

// Create a print instruction
Instruction printInstruction = factory.createPrintln("Hello, world!");

// Insert the print instruction at the beginning of the method
instructions.insert(printInstruction);

// Update the method in the JavaClass object
methodGen.setInstructionList(instructions);
javaClass.replaceMethod(method, methodGen.getMethod());
Java

In this example, a print statement is added to the beginning of the method someMethod. This is done by creating a MethodGen object from the existing method, creating a print instruction using InstructionFactory, inserting the print instruction at the beginning of the method’s instruction list, and then updating the method in the JavaClass object.

Sure, let’s explore more examples of BCEL’s capabilities.

Creating and Manipulating Fields

BCEL provides a FieldGen class that can be used to create and manipulate fields in a class. Here is an example of creating a new field:

// Create a new public, static integer field named 'newField'
FieldGen fieldGen = new FieldGen(ACC_PUBLIC | ACC_STATIC,
                                 Type.INT,
                                 "newField",
                                 javaClass.getConstantPool());

// Add the field to the class
javaClass.addField(fieldGen.getField());
Java

In this example, a new public, static integer field named newField is created and added to the class.

To modify an existing field, you can use the getField method of JavaClass to get a Field object, and then create a FieldGen object from that:

// Get the existing field
Field field = javaClass.getField("existingField");

// Create a FieldGen object from the existing field
FieldGen fieldGen = new FieldGen(field, javaClass.getConstantPool());

// Modify the field
fieldGen.setType(Type.DOUBLE);  // Change the field's type to double

// Update the field in the JavaClass object
javaClass.replaceField(field, fieldGen.getField());
Java

Manipulating Class Attributes

BCEL also allows you to manipulate class attributes. Here is an example of adding a new attribute to a class:

// Create a new attribute
Attribute newAttribute = new Unknown("AttributeName",
                                     new byte[]{1, 2, 3, 4},  // Attribute contents
                                     javaClass.getConstantPool());

// Add the attribute to the class
javaClass.addAttribute(newAttribute);
Java

In this example, a new attribute named “AttributeName” with the contents {1, 2, 3, 4} is added to the class.

Creating New Classes

Finally, BCEL provides a ClassGen class that can be used to create new classes. Here is an example of creating a new class:

// Create a new class named 'NewClass' that extends Object
ClassGen classGen = new ClassGen("NewClass",
                                 "java.lang.Object",
                                 "<generated>",
                                 ACC_PUBLIC | ACC_SUPER,
                                 null);

// Add a default constructor to the class
InstructionList il = new InstructionList();
InstructionFactory factory = new InstructionFactory(classGen);
il.append(InstructionFactory.createLoad(Type.OBJECT, 0));
il.append(factory.createInvoke("java.lang.Object", "<init>", Type.VOID, new Type[]{}, INVOKE_SPECIAL));
il.append(InstructionFactory.createReturn(Type.VOID));
MethodGen methodGen = new MethodGen(ACC_PUBLIC, Type.VOID, new Type[]{}, new String[]{}, "<init>", "NewClass", il, classGen.getConstantPool());
classGen.addMethod(methodGen.getMethod());

// Get the JavaClass object representing the new class
JavaClass newClass = classGen.getJavaClass();
Java

In this example, a new class named NewClass that extends Object is created. A default constructor is added to the class, and then a JavaClass object representing the new class is obtained.

These examples show just a few of the many ways you can use BCEL to create and manipulate Java class files. With its extensive capabilities, BCEL is a powerful tool for Java developers.