kajarigd
kajarigd

Reputation: 1309

In bytecode add a method to a particular line in a class using BCEL

I am new to BCEL for manipulating Java bytecode. I need to insert a new method into a particular line in a .class file using BCEL. The result should be a new .class file which contains the class with the newly inserted method.

I searched a lot online, but could not find a suitable code to follow. Can you please help me with this?

Thanks in advance!

Upvotes: 0

Views: 1568

Answers (1)

Peter
Peter

Reputation: 630

I used GeekyArticles to figure out BCEL, maybe it helps you to? http://www.geekyarticles.com/search/label/BCEL

Anyway, the following code works for me (Java 1.7)

Test.java:

public class Test {}

AddMain.java:

import java.io.IOException;
import org.apache.bcel.classfile.*;
import org.apache.bcel.generic.*;
import org.apache.bcel.*;

public class AddMain {

    static public void main(String args[]) {
        String className = (args.length >= 1) ? args[0] : "";
        JavaClass mod = null;
        try {
            mod = Repository.lookupClass(className);
        }
        catch (Exception e) {
            System.err.println("Could not get class " + className);
        }

        ClassGen modClass = new ClassGen(mod);
        ConstantPoolGen cp = modClass.getConstantPool();

        InstructionList il = new InstructionList();

        il.append(new GETSTATIC(cp.addFieldref("java.lang.System","out","Ljava/io/PrintStream;")));
        il.append(new PUSH(cp, "Hello World!"));
        il.append(new INVOKEVIRTUAL(cp.addMethodref("java.io.PrintStream","println","(Ljava/lang/String;)V")));
        il.append(new RETURN());

        MethodGen methodGen = new MethodGen(
            Constants.ACC_PUBLIC|Constants.ACC_STATIC, 
            Type.VOID, 
            new Type[]{new ArrayType(Type.STRING, 1)}, 
            new String[]{"args"}, 
            "main", 
            className, 
            il, 
            cp);

        methodGen.setMaxLocals();
        methodGen.setMaxStack();

        modClass.addMethod(methodGen.getMethod());
        modClass.update();

        try {
            JavaClass newClass = modClass.getJavaClass();
            String className2 = className.replace(".","/");
            newClass.dump(className2 + ".class");
            System.out.println("Class " + className + " modified");
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Then use these commands in your terminal:

Generate AddMain.class:

javac -cp bcel-5.2.jar:. AddMain.java; 

Generate Test.class:

javac Test.java; 

Inject method named "main" in class Test.class:

java -cp bcel-5.2.jar:. AddMain Test; 

Run Test.class to test:

java Test

And of course make sure you've got the bcel-5.2.jar file in that directory as well.

As far as I know you can't control the position of the injected method, but I'm not sure about that..

Upvotes: 1

Related Questions