1

我正在尝试使用 javassist 修改类构造函数中的以下字段:

Label Label1 = new Label(new StringBuilder().append(user.name));
Label Label2 = new Label(new StringBuilder().append(user.time.toString());

我想将文本添加到 2 个标签。可以使用 getText() 和 setText() 访问和设置文本。

我怎么能做到这一点?

4

1 回答 1

2

最简单的方法是使用 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.

于 2012-12-05T11:29:46.210 回答