Oussama Achech
Oussama Achech

Reputation: 131

Generate a code from a java class that uses another java class (BCEL)

I am trying to generate(and modify) the code of an output class from another class using the ByteCode Engineering Library (by Apache) .

String class_name = c_gen.getClassName();
    Method[] Methods = c_gen.getMethods();

    for (int i=0;i<Methods.length;i++)
    {
        MethodGen m_gen = new MethodGen(Methods[i], class_name, cpg);
        InstructionList il = m_gen.getInstructionList();
        InstructionHandle h;
           il.insert(h,factory.createInvoke("ClassName","printSomething",   Type.VOID,new Type[]{Type.STRING}, INVOKESTATIC));
    }

so I am trying to call printSomething from ClassName for every method.The problem is that I don't know how to actually pass the string argument to the method printSomething

Upvotes: 1

Views: 171

Answers (1)

Kenney
Kenney

Reputation: 9093

You will need to push the string argument on the stack before the invokestatic. This is done with the LDC opcode. Something like:

il.insert( new LDC(cpg.addString("MyString")));

The outline looks like this:

JavaClass clazz = Repository.lookupClass( class_name );
ClassGen c_gen = new ClassGen( clazz );
ConstantPoolGen cpg = new ConstantPoolGen( clazz.getConstantPool() );
InstructionFactory factory = new InstructionFactory( c_gen, cpg );

Methods [] methods = clazz.getMethods();

for ( int i = 0; i < methods.length; i ++ )
{
    if ( m.isAbstract() || m.isNative() || .... )
        continue;

    MethodGen m_gen = new MethodGen( methods[i], class_name, cpg );
    InstructionList il = m_gen.getInstructionList();

    il.insert( factory.createInvoke("ClassName", "printSomething",
        Type.VOID, new Type[]{Type.STRING}, INVOKESTATIC) );
    il.insert( factory.createPush( "StringToPrint" ) );

    methods[i] = m_gen.getMethod();
}

clazz.setConstantPool( cpg.getFinalConstantPool() );
clazz.setMethods( methods ); // might be redundant

clazz.dump( new File( .... ) );

A few notes:

  • Since we're inserting, every insert will prepend to the method. This is why we first insert the instruction opcode, and then the arguments (in reverse), so that the actual sequence will be ldc #stringref; invokestatic #methodref.
  • We need to replace the ConstantPool and the Methods with our modified versions of them.

Upvotes: 1

Related Questions