简单的部分
方法insertAt(int 行号, 字符串 src)CtMethod 对象中存在的内容允许注入编写的代码src before给定行中的代码。
例如,采用以下(简单)示例程序:
public class TestSubject {
public static void main(String[] args) {
TestSubject testSubject = new TestSubject();
testSubject.print();
}
private void print() {
System.out.println("One"); // line 9
System.out.println("Two"); // line 10
System.out.println("Three"); // line 11
}
}
通过简单的编码(记住方法变量必须是 CtMethod 表示print方法):
// notice that I said line 10, which is where the sysout of "two" is
method.insertAt(10, true, "System.out.println(\"one and an half\");");
将在类中注入新的 sysout 指令。新类的输出将是:
one
one and an half
two
three
困难的部分
Javassist 没有提供删除一行代码的简单方法,因此如果您确实想替换它,您将别无选择,只能破解。
怎么做?好吧,让我向您介绍一下您的新朋友(如果您还不认识),代码属性 object.
CodeAttribute 对象负责保存表示方法流程的字节码,除了 code 属性之外,还有另一个属性称为行号属性这可以帮助您将行号映射到字节码数组中。所以总结一下这个对象已经有你需要的一切了!
以下示例中的想法非常简单。将字节码数组中的字节与应删除的行相关联,并用无操作代码替换这些字节。
再次强调,method 是 method 的 CtMethod 表示print
// let's erase the sysout "Two"
int lineNumberToReplace = 10;
// Access the code attribute
CodeAttribute codeAttribute = method.getMethodInfo().getCodeAttribute();
// Access the LineNumberAttribute
LineNumberAttribute lineNumberAttribute = (LineNumberAttribute) codeAttribute.getAttribute(LineNumberAttribute.tag);
// Index in bytecode array where the instruction starts
int startPc = lineNumberAttribute.toStartPc(lineNumberToReplace);
// Index in the bytecode array where the following instruction starts
int endPc = lineNumberAttribute.toStartPc(lineNumberToReplace+1);
System.out.println("Modifying from " + startPc + " to " + endPc);
// Let's now get the bytecode array
byte[] code = codeAttribute.getCode();
for (int i = startPc; i < endPc; i++) {
// change byte to a no operation code
code[i] = CodeAttribute.NOP;
}
在中运行此修改originalTestSubject 类将生成具有以下输出的注入类:
one
three
加起来
当您需要添加一行并仍保留现有行时,您只需使用中给出的示例简单的部分如果要替换该行,则必须首先使用中给出的示例删除现有行困难的部分然后使用第一个示例注入新行。
另请记住,在示例中,我假设您已经熟悉了 javassist 的基础知识,仅向您展示了有趣的部分,而不是全部内容。这就是为什么,例如,在示例中没有 ctClass.writeFile...您仍然需要这样做,我只是将其省略,因为我确实希望您应该知道您必须这样做。
如果您在代码示例中需要任何额外帮助,请直接询问。我很乐意提供帮助。