javassist ; отсутствует

#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 предназначенный для замены ? на фиксированное значение.