我想在运行时重命名java类中的字段。此外,任何访问该字段的方法;它是读还是写;我需要修改它以使用新名称而不是旧名称.
所有这一切都将在前主要方法中完成.
作为一个示例,给出以下代码:
public class Class1
{
String strCompany;
public String Test()
{
strCompany = "TestCompany";
return strCompany;
}
}在上面的类中,我需要将"strCompany“字段更改为"strCompany2",此外,我还需要方法测试来使用新名称而不是旧名称.
可以使用来自setName类的ctField方法来更改字段名,但如何修改方法主体以使用新名称。
发布于 2014-11-28 17:48:32
嗯,我很晚才知道答案,但我希望你仍然觉得它有用(或者至少有人需要这样的东西)。
尽管您可以使用注释中建议的低级别字节码api,但javassist确实允许您使用更高级别的API (我推荐的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文件夹中准备好使用strCompany2而不是strCompany。:-)
侧纹
请记住,CodeConverter真正做的是在类常量池中创建一个新条目,并将有关旧字段的所有引用重新路由到定义“新”(read重命名)字段的条目。
因此,在Class1示例中,下面是发生的情况:
注入前常池
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注入后恒定池
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帧,它们代表了新字段的定义。通常这不是一个问题,但我宁愿提前提及。
https://stackoverflow.com/questions/26737226
复制相似问题