问题
I am trying to modify the following fields in a class constructor using javassist :
Label Label1 = new Label(new StringBuilder().append(user.name));
Label Label2 = new Label(new StringBuilder().append(user.time.toString());
I want to prepend text to the 2 labels. The text can be accessed and set using getText() and setText().
How could I achieve this?
回答1:
The simplest approach is to use the ability to modify the constructor body with java code and let javassist create the bytecode.
So you can easily do something like:
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/");
Also keep in mind that if the prefix you'll be adding, instead of a String is a static field in other class you must give the full qualified name of that class, for example: .append(package1.package2.SomeClass.SomeField)
.
This is needed because imports
are only at source level, when you look at the JVM bytecode all class references are to the full qualified name.
More information on how to achieve this kind of modifications with Javassist can be found in the javasssist's documentation, section 4.1 Inserting source text at the beginning/end of a method body
UPDATE
Whenever you are writing Java code for javassist to inject, keep in mind that you must use full qualified class names, otherwise javassist's classpool wouldn't be able to find the classes resulting in a javassist.CannotCompileException
.
来源:https://stackoverflow.com/questions/13715986/use-javassist-to-modify-fields-that-use-getters-and-setters-in-a-class-construct