gpt4 book ai didi

java - 在运行时在 pre-main 方法中使用 javassist 重命名字段(java 检测)

转载 作者:塔克拉玛干 更新时间:2023-11-03 05:28:58 32 4
gpt4 key购买 nike

我想在运行时重命名 java 类中的字段。此外,访问该字段的任何方法;无论是读还是写;我需要修改它以使用新名称而不是旧名称....

所有这些都将在 pre-main 方法中完成...

作为一个例子,给定以下代码:

public class Class1
{
String strCompany;

public String Test()
{
strCompany = "TestCompany";
return strCompany;
}
}

在上面的类中,我需要将字段“strCompany”更改为“strCompany2”,此外我还需要方法 Test 来使用新名称而不是旧名称....

可以使用 ctField 类中的 setName 方法更改字段名称,但如何修改方法主体以使用新名称。

最佳答案

好吧,我回答晚了,但我希望你仍然觉得它有用(或者至少其他人需要这种东西)。

即使您可以使用评论中建议的 Raphw 之类的低级字节码 API,javassist 也允许您使用更高级别的 API(我推荐)来执行此操作。

我将在下面介绍的解决方案将更改字段名称并将所有 引用从旧字段名称更改为新字段名称,这可能正是您想要的,因为您重命名字段。

代码

让我们使用您的 Class1 示例。

  ClassPool classpool = ClassPool.getDefault();
CtClass ctClass = classpool.get(Class1.class.getName());
CtField field = ctClass.getField("strCompany");
CodeConverter codeConverter = new CodeConverter();
codeConverter.redirectFieldAccess(field, ctClass, "strCompany2");
ctClass.instrument(codeConverter);

field.setName("strCompany2");
ctClass.writeFile("./injectedClasses");

我假设访问 CtField 并设置其名称 - 由于您的问题 - 您已经知道如何去做。“重新连接”所有字段引用的技巧是使用 CodeConverter 完成的这将替换对 CtField 字段 的所有引用,以替换对 ctClass 中名为 strCompany2 的字段的引用(恰好是同一类)。请记住,这需要在将该字段重命名为 strCompany2 之前完成。

在此运行结束时,您将在 injectedClasses 文件夹中准备好新的 Class1,以使用 strCompany2 而不是 strCompany。 :-)

旁注

请记住,CodeConverter 真正做的是在类常量池中创建一个新条目,并将所有引用从有关旧字段的条目重新路由到定义"new"(读取重命名)字段的条目。

因此在 Class1 示例中,发生了以下情况:

注入(inject)前的常量池

Constant pool:
#1 = Class #2 // test/Class1
#2 = Utf8 test/Class1
#3 = Class #4 // java/lang/Object
#4 = Utf8 java/lang/Object
#5 = Utf8 strCompany
#6 = Utf8 Ljava/lang/String;
#7 = Utf8 <init>
#8 = Utf8 ()V
#9 = Utf8 Code
#10 = Methodref #3.#11 // java/lang/Object."<init>":()V
#11 = NameAndType #7:#8 // "<init>":()V
#12 = Utf8 LineNumberTable
#13 = Utf8 LocalVariableTable
#14 = Utf8 this
#15 = Utf8 Ltest/Class1;
#16 = Utf8 test
#17 = Utf8 ()Ljava/lang/String;
#18 = String #19 // TestCompany
#19 = Utf8 TestCompany
#20 = Fieldref #1.#21 // test/Class1.strCompany:Ljava/lang/String;
#21 = NameAndType #5:#6 // strCompany:Ljava/lang/String;
#22 = Utf8 SourceFile
#23 = Utf8 Class1.java

注入(inject)后的常量池

Constant pool:
#1 = Class #2 // test/Class1
#2 = Utf8 test/Class1
#3 = Class #4 // java/lang/Object
#4 = Utf8 java/lang/Object
#5 = Utf8 strCompany
#6 = Utf8 Ljava/lang/String;
#7 = Utf8 <init>
#8 = Utf8 ()V
#9 = Utf8 Code
#10 = Methodref #3.#11 // java/lang/Object."<init>":()V
#11 = NameAndType #7:#8 // "<init>":()V
#12 = Utf8 LineNumberTable
#13 = Utf8 LocalVariableTable
#14 = Utf8 this
#15 = Utf8 Ltest/Class1;
#16 = Utf8 test
#17 = Utf8 ()Ljava/lang/String;
#18 = String #19 // TestCompany
#19 = Utf8 TestCompany
#20 = Fieldref #1.#21 // test/Class1.strCompany:Ljava/lang/String;
#21 = NameAndType #5:#6 // strCompany:Ljava/lang/String;
#22 = Utf8 SourceFile
#23 = Utf8 Class1.java
#24 = Utf8 strCompany2
#25 = NameAndType #24:#6 // strCompany2:Ljava/lang/String;
#26 = Fieldref #1.#25 //test/Class1.strCompany2:Ljava/lang/String;

在这种情况下,通过重写一个字段,您的 constantPool 增长了 3 帧,代表新字段的定义。通常这不是问题,但我宁愿提前提及。

关于java - 在运行时在 pre-main 方法中使用 javassist 重命名字段(java 检测),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26737226/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com