我正在尝试使用 javassist 修改类构造函数中的以下字段:
Label Label1 = new Label(new StringBuilder().append(user.name));
Label Label2 = new Label(new StringBuilder().append(user.time.toString());
我想将文本添加到 2 个标签。可以使用 getText() 和 setText() 访问和设置文本。
我怎么能做到这一点?
我正在尝试使用 javassist 修改类构造函数中的以下字段:
Label Label1 = new Label(new StringBuilder().append(user.name));
Label Label2 = new Label(new StringBuilder().append(user.time.toString());
我想将文本添加到 2 个标签。可以使用 getText() 和 setText() 访问和设置文本。
我怎么能做到这一点?
最简单的方法是使用 java 代码修改构造函数主体并让 javassist 创建字节码的能力。
因此,您可以轻松地执行以下操作:
ClassPool classPool = ClassPool.getDefault();
CtClass ctClass = classPool.get("package1.package2.ClassToInject");
/* Notice that in this case I'm going for the default constructor
* If you want another constructor you just have to materialize the CtClass, for
* each parameter and pass them in the CtClass Array
*/
CtConstructor declaredConstructor = ctClass.getDeclaredConstructor(new CtClass[] {});
/* Now that you have your constructor you can use insertAfter(), this means, it
* will be the last thing to be executed in the constructor. We'll rewrite the
* label1 field with our new value. Notice that the string in insertAfter
* argument is a regular, valid java code line.
*/
declaredConstructor.insertAfter("Label1 = new package3.package4.Label(new StringBuilder().append(\"somePrefixMayBeAStringOrAVariableInScope\").append(user.name));");
// and finally we write the bytecode
ctClass.writeFile("/somePathToPutTheInjectedClassFile/");
另请记住,如果您要添加的前缀而不是 String 是其他类中的静态字段,则您必须提供该类的完整限定名,例如:.append(package1.package2.SomeClass.SomeField)
.
这是必需的,因为imports
仅在源代码级别,当您查看 JVM 字节码时,所有类引用都指向完整的限定名称。
有关如何使用 Javassist 进行此类修改的更多信息,请参见 javasssist 的文档,第4.1 节在方法体的开头/结尾插入源文本
更新
每当您为 javassist 编写 Java 代码以进行注入时,请记住您必须使用完全限定的类名,否则 javassist 的类池将无法找到导致javassist.CannotCompileException
.