jsr:使用javassist insertAfter时,字节码中存在错误

时间:2015-07-29 02:13:57

标签: java javassist bytecode-manipulation

我尝试使用" insertAfter()"之后的方法使用javassist添加代码。 但运行代码时报告错误:

try {
            CtClass ctClass = ClassPool.getDefault().get(className.replace('/', '.'));
            CtMethod ctMethod = ctClass.getDeclaredMethod("display1");
            ctMethod.insertBefore(
                    "name=\"我是name!这次用javassist了哦!\";" +
                    "value=\"我是value!\";" +
                    "System.out.println(\"我是加进去的哦,哈哈:\" + name);"
            );
            ctMethod.insertAfter("System.out.println(value);");
            return ctClass.toBytecode();
        } catch (Exception e) {
            e.printStackTrace();
        }

运行后,报告错误:

线程中的异常" main" java.lang.VerifyError:错误指令:a8

异常详细信息:

位置:

com/atlassian/api/examples/ForASMTestClass.display1()V @62: jsr

原因:

Error exists in the bytecode

字节码:

0x0000000: 2a12 28b5 0026 2a12 2cb5 002a b200 2ebb

0x0000010: 0030 59b7 0032 1234 b600 382a b400 3ab6

0x0000020: 003c b600 40b6 0042 b200 122a b400 18b6

0x0000030: 001a b200 122a b400 20b6 001a 014d a800

0x0000040: 04b1 4cb2 0044 2ab4 0046 b600 48a9 01  

at transformer.modifycode.InstrumentationMain.main(InstrumentationMain.java:7)

加载类:java / lang / VerifyError

使用javap获取字节码:

  public void display1();
descriptor: ()V
flags: ACC_PUBLIC
Code:
  stack=4, locals=4, args_size=1
     0: aload_0
     1: ldc           #43                 // String xx
     3: putfield      #41                 // Field name:Ljava/lang/String;
     6: getstatic     #18                 // Field java/lang/System.out:Ljava/io/PrintStream;
     9: aload_0
    10: getfield      #24                 // Field name:Ljava/lang/String;
    13: invokevirtual #26                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
    16: getstatic     #18                 // Field java/lang/System.out:Ljava/io/PrintStream;
    19: aload_0
    20: getfield      #32                 // Field value:Ljava/lang/String;
    23: invokevirtual #26                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
    26: goto          42
    29: astore_1
    30: getstatic     #18                 // Field java/lang/System.out:Ljava/io/PrintStream;
    33: aload_0
    34: getfield      #32                 // Field value:Ljava/lang/String;
    37: invokevirtual #26                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
    40: aload_1
    41: athrow
    42: getstatic     #18                 // Field java/lang/System.out:Ljava/io/PrintStream;
    45: aload_0
    46: getfield      #32                 // Field value:Ljava/lang/String;
    49: invokevirtual #26                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
    52: aconst_null
    53: astore_3
    54: jsr           58
    57: return
    58: astore_2
    59: getstatic     #45                 // Field java/lang/System.out:Ljava/io/PrintStream;
    62: aload_0
    63: getfield      #47                 // Field value:Ljava/lang/String;
    66: invokevirtual #49                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
    69: ret           2
  Exception table:
     from    to  target type
         6    29    29   any
  LineNumberTable:
    line 11: 6
    line 12: 16
    line 13: 26
    line 14: 30
    line 15: 40
    line 14: 42
    line 16: 52
  LocalVariableTable:
    Start  Length  Slot  Name   Signature
        0      58     0  this   Lcom/test/swing/ForASMTestClass;
  StackMapTable: number_of_entries = 2
    frame_type = 87 /* same_locals_1_stack_item */
      stack = [ class java/lang/Throwable ]
    frame_type = 12 /* same */

目前,我可以使用ASM在方法之后添加代码,但由于很多字节码需要手动编写,所以效率不高。

2 个答案:

答案 0 :(得分:1)

在你的javap命令输出中,如果你还提供了类文件标题(你可以通过使用-v来实现),这将显示你的类的主要版本。

根据您提供的信息,我认为该类的主要版本是51(java 7)或52(java 8),因为在这种情况下不支持jrs操作码。< / p>

您可以阅读here(感谢@Holger提供直接web reference链接。在第一次编辑中,我使用了book reference,因为我找不到直接参考):

  

如果类文件版本号为51.0或更高,则jsr操作码或jsr_w操作码都不会出现在代码数组中。

这可以解释为什么你会得到验证错误。

如果我不得不猜到为什么那个操作码出现在那里我会说你使用的是一个较旧的javassist版本仍然使用JSR操作码(由finally语句使用)实现insertAfterMethod,它可能会被修复,如果你使用最新的javassist版本。

我知道这个答案更多地基于对实际&#34;确凿证据的猜测&#34;并且可能不准确。如果问题不是我所描述的,请编辑您的答案以添加更多信息,例如:

  • 班级的标题信息,包括次要版本和主要版本
  • javap在 javassist操作
  • 之前输出
  • javassist version
  • 您正在运行
  • 上的代码的当前JVM(品牌和版本)

答案 1 :(得分:0)

升级Javassist(3.25.0-GA)有助于为我解决此问题。