Самый простой подход — использовать возможность модифицировать тело конструктора с помощью 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/");
Также имейте в виду, что если префикс, который вы будете добавлять, вместо строки является статическим полем в другом классе, вы должны указать полное имя этого класса, например: .append(package1.package2.SomeClass.SomeField)
.
Это необходимо, потому что imports
находятся только на уровне исходного кода, когда вы смотрите на байт-код JVM, все ссылки на классы относятся к полному квалифицированному имени.
Дополнительную информацию о том, как добиться такого рода изменений с помощью Javassist, можно найти в документации javasssist, раздел 4.1 Вставка исходного текста в начало/конец тела метода
ОБНОВЛЕНИЕ
Всякий раз, когда вы пишете код Java для внедрения javassist, имейте в виду, что вы должны использовать полные имена классов, иначе пул классов javassist не сможет найти классы, что приведет к ошибке javassist.CannotCompileException
.
person
pabrantes
schedule
05.12.2012