#java #bytecode #javassist
#java #байт-код #javassist
Вопрос:
Кто-нибудь может сказать, что не так с моим кодом? при использовании javassist для вставки кода отображается ошибка «Вызвано: ошибка компиляции: ; отсутствует»; Но я дважды проверяю, там нет; отсутствует вообще. Есть ли здесь какое-то ограничение javassist?
ClassPool cp = ClassPool.getDefault();
cp.importPackage("com.mysql.cj");
CtClass cc = cp.get(clzname);
CtMethod ms = cc.getDeclaredMethod(
"execute");
StringBuilder sb = new StringBuilder();
sb.append("String sql = ((PreparedQuery) this.query).getOriginalSql();");
sb.append("QueryBindings bindings = ((PreparedQuery) this.query).getQueryBindings();n"
" for (BindValue o : bindings.getBindValues()) {n"
" sql = sql.replaceFirst("\\?", new String(o.getByteValue()));n"
" }");
sb.append(
"System.out.println( sql);");
ms.insertBefore(sb.toString());
byteCode = cc.toBytecode();
Комментарии:
1. сложно визуально проанализировать эти строки добавления, поэтому, если вы закомментируете свои строки добавления, у вас все еще есть; ошибка? Если это так, вам, вероятно, нужно показать нам другую часть вашего кода. Не указывает ли ваше сообщение об ошибке на определенную строку?
2. Я бы дважды проверил escape-последовательности
("\\?",
— эти вещи легко ошибиться.
Ответ №1:
Javadoc для insertBefore говорит:
https://www.javassist.org/html/javassist/CtBehavior.html#insertBefore (java.lang.Строка)
Параметры: src — исходный код, представляющий вставленный байт-код. Это должен быть один оператор или блок.
Итак, заключите код в фигурные скобки, чтобы это был единый блок.
Комментарии:
1. После заключения вашего кода в фигурные скобки он по-прежнему показывает ту же ошибку ….. [ошибка источника] ; отсутствует
Ответ №2:
Я решил свою ошибку, заменив цикл for.
Кажется, javaassit не поддерживает удобный цикл for, его необходимо изменить в формат for(int i= 0; i< lenth; i );
И благодаря @kutschem , код также необходимо заключить в фигурные скобки.
ClassPool cp = ClassPool.getDefault();
cp.importPackage("com.mysql.cj");
CtClass cc = cp.get(clzname);
CtMethod ms = cc.getDeclaredMethod(
"execute");
ms.insertBefore("{n"
" String sql = ((PreparedQuery) this.query).getOriginalSql();n"
" QueryBindings bindings = ((PreparedQuery) this.query).getQueryBindings();n"
" for (int i =0; i < bindings.getBindValues().length; i ) sql = sql.replaceFirst("\\?", new String(bindings.getBindValues()[i].getByteValue()));n"
" System.out.println(sql);n"
" }");
byteCode = cc.toBytecode();
Комментарии:
1. Компилятор в javassist очень прост и с большим количеством ограничений. например, generics, vargs, (un /)boxing. Смотрите github.com/jboss-javassist/javassist/wiki/Tutorial-3
Ответ №3:
В дополнение к переносу вашего кода в фигурные скобки, как сказал @kutschem, у меня также есть идея для вас, как проще объединить вашу строку, не используя StringBuilder
. В качестве положительного побочного эффекта вы также получаете разрывы строк:
String codeToBeInserted = String.join("n",
"{",
" String sql = ((PreparedQuery) this.query).getOriginalSql();",
" QueryBindings bindings = ((PreparedQuery) this.query).getQueryBindings();",
" for (BindValue o : bindings.getBindValues()) {",
" sql = sql.replaceFirst("\\?", new String(o.getByteValue()));",
" }",
" System.out.println(sql);",
"}"
);
System.out.println(codeToBeInserted);
String.join
доступно с Java 8. Вывод на консоль будет:
{
String sql = ((PreparedQuery) this.query).getOriginalSql();
QueryBindings bindings = ((PreparedQuery) this.query).getQueryBindings();
for (BindValue o : bindings.getBindValues()) {
sql = sql.replaceFirst("\?", new String(o.getByteValue()));
}
System.out.println(sql);
}
Для меня ваш код выглядит синтаксически нормально, особенно replaceFirst
предназначенный для замены ?
на фиксированное значение.