Renaming a field using javassist at run time in a preliminary main method (Java toolkit)

I want to rename a field inside a java class at runtime. In addition, Any method that accesses this field to read or write; I need to change it to use the new name instead of the old name ....

All this will be done inside the main method ...

As an exmaple, given the following code:

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

In the class above, I need to change the "strCompany" field to "strCompany2", in addition, I need the Test method to use the new name instead of the old name ....

changing the field name can be done using the setName method from the ctField class, but how can I change the body of the method to use the new name.

+6
source share
1 answer

Well, I was late for the answer, but I hope you find it useful anyway (or at least to someone else who needs it).

Even if you can use low-level api bytecode, for example, Raphw suggested in the javassist comment allows you to do this with a higher-level API (which I recommend).

The solution that I will give below will change the field name and change all references from the old field name to the new one, which is likely to be what you want, since you are renaming the field.

Code

Use the Class1 example.

  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"); 

Accessing and Defining CtField I assume - on your question - you already know how to do this. The trick of โ€œredoingโ€ all field references is done using CodeConverter which will replace all links to the CtField field for references to a field named strCompany2 in ctClass (which happens in the same class). Keep in mind that this needs to be done before by renaming the field to strCompany2.

At the end of this run, you'll have a new Class1 class in the embeddedbedclasses folder, ready to use strCompany2 instead of strCompany .:-)

Sidenote

Keep in mind that what CodeConverter really does is create a new entry in the Constant Pool class and redirect all links from the old field entry to the field that defines the "new" (read renamed) field.

So in the Class1 example, this is what happens:

Permanent Pool BEFORE Injection

 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 

Permanent pool AFTER injection

 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; 

In this case, with one rewrite field, your constantPool has increased by 3 frames, which are the definition of a new field. This is usually not a problem, but, nevertheless, I rather mentioned this in advance.

+2
source

Source: https://habr.com/ru/post/977713/


All Articles