容易的部分
CtMethod对象中存在的方法insertAt(int lineNumber,String
src)允许在给定行中的代码
之前* 注入以 src 编写的代码。 *
例如,使用以下(简单)示例程序:
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表示形式):
// 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没有提供简单的方法来删除一行代码,因此,如果您真的想替换它,那么除了破解之外,别无选择。
怎么做?好吧,让我向您介绍您的新朋友(如果您还不知道)CodeAttribute对象。
CodeAttribute对象负责保存表示方法流的字节码,该代码属性还具有另一个名为LineNumberAttribute的属性,该属性可帮助您将行号映射到字节码数组中。因此,总结该对象即可满足您的所有需求!
以下示例中的想法非常简单。将字节码数组中的字节与应删除的行相关联,并用无操作码替换字节。
再一次,method是方法 print 的CtMethod表示形式 __
// let's erase the sysout "Two" int lineNumberToReplace = 10; // Access the pre attribute CodeAttribute preAttribute = method.getMethodInfo().getCodeAttribute(); // Access the LineNumberAttribute LineNumberAttribute lineNumberAttribute = (LineNumberAttribute) preAttribute.getAttribute(LineNumberAttribute.tag); // Index in bytepre array where the instruction starts int startPc = lineNumberAttribute.toStartPc(lineNumberToReplace); // Index in the bytepre 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 bytepre array byte[] pre = preAttribute.getCode(); for (int i = startPc; i < endPc; i++) { // change byte to a no operation pre pre[i] = CodeAttribute.NOP; }在 原始 TestSubject类中运行此修改,将导致注入的类具有以下输出:
one three
加起来
当你有需要添加一条线,仍保持现有的一个,你只需要使用给出的例子 比较容易的部分 ,如果你想更换线路,您必须先删除使用中给出的例子既有线 的硬部分
,然后使用第一个示例注入新行。
还请记住,在示例中,我假设您已经对javassist的基础知识感到满意,只显示了多汁的部分,而不是全部内容。这就是为什么,例如,在示例中没有ctClass.writeFile
…您仍然需要这样做,我只是省略了它,因为我希望您应该知道您必须这样做。
如果您在代码示例中需要任何其他帮助,请询问。我很乐意提供帮助。



