在javassist API中,似乎没有直接的方法可以在CodeAttribute属性中手动添加任何内容。

给出以下示例:

CtMethod m;
m.getMethodInfo().getCodeAttribute().setAttribute(???);


这似乎是更改属性的唯一方法。但是,不可能检索原始属性并对其进行修改(它返回AttributeInfo的列表),也不存在用于StackMapTable的公共构造函数,这似乎是唯一被接受的输入。

有人知道该怎么做吗?

最佳答案

CodeAttribute对象负责保存表示方法流的字节码。您可以使用它来迭代表示方法逻辑的字节码。

这基本上意味着它代表编译的方法本身。我知道您可以使用此对象手动修改字节码本身,例如删除两行之间的所有指令:

// erase from line 4 to 6
int startingLineNumber= 6;
// Access the code attribute
CodeAttribute codeAttribute = mymethod.getMethodInfo().getCodeAttribute();

LineNumberAttribute lineNumberAttribute = (LineNumberAttribute)      codeAttribute.getAttribute(LineNumberAttribute.tag);

// Index in bytecode array where we start to delete
int firstIndex = lineNumberAttribute.toStartPc(startingLineNumber);

// Index in the bytecode where the first instruction that we keep starts
int secondIndex = lineNumberAttribute.toStartPc(startingLineNumber+2);

// go through the bytecode array
byte[] code = codeAttribute.getCode();
for (int i = firstIndex ; i < secondIndex ; i++) {
   // set the bytecode of this line to No OPeration
   code[i] = CodeAttribute.NOP;
}


但是,这可能确实很棘手,并且很容易失控。
我建议要做的是只是从头创建一个新的CodeAttribute并将其替换为您的方法,以避免令人不愉快的意外:

 ClassFile cf = ...;
 MethodInfo minfo = cf.getMethod("yourMethod");
 Bytecode code = new Bytecode(cf.getConstPool());
 // insert your logic here
 code.addAload(0);
 code.addInvokespecial("java/lang/Object", MethodInfo.nameInit, "()V");
 code.addReturn(null);
 code.setMaxLocals(1);

 MethodInfo minfo = new MethodInfo(cf.getConstPool(), MethodInfo.nameInit, "()V");
 minfo.setCodeAttribute(code.toCodeAttribute());


但是,由于直接处理字节码,因此此方法也可能具有很大的风险。最好的办法就是删除您的方法,然后使用您的逻辑添加一个新方法。

09-30 18:40