从使用另一个java类(BCEL)的java类生成代码

时间:2015-10-31 22:13:47

标签: bcel

我正在尝试使用ByteCode工程库(由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));
    }

所以我试图从ClassName为每个方法调用printSomething。问题是我不知道如何将字符串参数实际传递给方法printSomething

1 个答案:

答案 0 :(得分:1)

您需要在invokestatic之前在字符串上推送字符串参数。这是通过LDC操作码完成的。类似的东西:

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

大纲如下:

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( .... ) );

一些注意事项:

  • 由于我们正在插入,因此每个插入都将添加到该方法之前。这就是为什么我们首先插入指令操作码,然后插入参数(反过来),以便实际序列为ldc #stringref; invokestatic #methodref
  • 我们需要将ConstantPool和Methods替换为它们的修改版本。