2013-10-24 45 views
0

我碰到一個無聊的錯誤:BCEL可以生成LocalVariableTable嗎?

Exception in thread "main" java.lang.VerifyError: Bad type on operand stack in method 
     net.madz.lifecycle.demo.standalone.ServiceOrder.allocateResources(JJJ)V at offset 27 

我不太理解錯誤的意思。

我已經寫了一個類,並生成一個階層,他們看起來很相似:

寫道:

public void allocateResources(long arg0, long truckResourceId, long arg2) { 
    /* L23 */ 
    0 new 2; 
    3 dup; 
    4 invokespecial 3;  /* net.madz.lifecycle.solutionOne.InterceptorController() */ 
    7 astore 7;    /* controller */ 
    /* L24 */ 
    9 new 4; 
    12 dup; 
    13 aload_0;    /* this */ 
    14 invokevirtual 5;  /* java.lang.Class getClass() */ 
    17 aload_0;    /* this */ 
    18 ldc 6;     /* "allocateResources" */ 
    20 iconst_3; 
    21 anewarray 7;   /* new java.lang.Class[] */ 
    24 dup; 
    25 iconst_0; 
    26 getstatic 8;   /* java.lang.Long.TYPE */ 
    29 aastore; 
    30 dup; 
    31 iconst_1; 
    32 getstatic 8;   /* java.lang.Long.TYPE */ 
    35 aastore; 
    36 dup; 
    37 iconst_2; 
    38 getstatic 8;   /* java.lang.Long.TYPE */ 
    41 aastore; 
    42 invokespecial 9;  /* net.madz.lifecycle.solutionOne.InterceptContext(java.lang.Class summaryPlanId, java.lang.Object arg1, java.lang.String truckResourceId, java.lang.Class[] arg3) */ 
    45 astore 8;    /* context */ 
    /* L26 */ 
    47 aload 7;    /* controller */ 
    49 aload 8;    /* context */ 
    51 new 10; 
    54 dup; 
    55 aload_0;    /* this */ 
    56 lload_1;    /* summaryPlanId */ 
    57 lload_3;    /* truckResourceId */ 
    58 lload 5;    /* plangResourceId */ 
    60 invokespecial 11;  /* net.madz.lifecycle.solutionOne.ServiceOrder$1(net.madz.lifecycle.solutionOne.ServiceOrder summaryPlanId, long arg1, long truckResourceId, long arg3) */ 
    63 invokevirtual 12;  /* java.lang.Object exec(net.madz.lifecycle.solutionOne.InterceptContext arg0, java.util.concurrent.Callable truckResourceId) */ 
    66 pop; 
    /* L34 */ 
    67 return; 
} 

生成:

public void allocateResources(long arg0, long arg1, long arg2) { 
    0 new 77; 
    3 dup; 
    4 invokespecial 78;  /* net.madz.lifecycle.solutionOne.InterceptorController() */ 
    7 astore 7; 
    9 new 80; 
    12 dup; 
    13 ldc 7; 
    15 aload_0; 
    16 ldc 81;    /* "allocateResources" */ 
    18 iconst_3; 
    19 anewarray 83;   /* new java.lang.Class[] */ 
    22 dup; 
    23 iconst_0; 
    24 getstatic 88;   /* java.lang.Long.TYPE */ 
    27 aastore; 
    28 dup; 
    29 iconst_1; 
    30 getstatic 88;   /* java.lang.Long.TYPE */ 
    33 aastore; 
    34 dup; 
    35 iconst_2; 
    36 getstatic 88;   /* java.lang.Long.TYPE */ 
    39 aastore; 
    40 invokespecial 91;  /* net.madz.lifecycle.solutionOne.InterceptContext(java.lang.Class arg0, java.lang.Object arg1, java.lang.String arg2, java.lang.Class[] arg3) */ 
    43 astore 8; 
    45 aload 7; 
    47 aload 8; 
    49 new 93; 
    52 dup; 
    53 aload_0; 
    54 lload_1; 
    55 lload_3; 
    56 lload 5; 
    58 invokespecial 96;  /* net.madz.lifecycle.demo.standalone.ServiceOrder$5(net.madz.lifecycle.demo.standalone.ServiceOrder arg0, long arg1, long arg2, long arg3) */ 
    61 invokevirtual 100;  /* java.lang.Object exec(net.madz.lifecycle.solutionOne.InterceptContext arg0, java.util.concurrent.Callable arg1) */ 
    64 pop; 
    65 return; 
} 

因爲它說:「在操作數壞類型堆棧中的方法net.madz.lifecycle.demo.standalone.ServiceOrder.allocateResources(JJJ)V at offset 27「

是不是「27 aastore」?這導致了這種異常?在寫的版本類,我的意思是我寫了一個java文件,並將其編譯到類文件。我使用this.getClass()加載類引用,因此在寫入版本中,「offset」13和14是「aload_0;」和「invokevirtual 5」但在生成的版本中,我使用偏移量爲13的「ldc」直接引用類,因此兩個版本無法精確對齊。

通常如何診斷這些問題以及如何在運行時監視操作數堆棧,BCEL是否可以將LocalVariableTable生成到類文件中?

回答

0

最後,我嘗試利用BCELifier從生成和寫入的類文件生成Java代碼,並且我發現它們之間的差異。

public static void main(String[] args) throws Throwable { 
    final JavaClass outerClass = Repository.lookupClass(ServiceOrder.class.getName()); 
    StringRepresentation s = new StringRepresentation(outerClass); 
    System.out.println(s); 
    BCELifier fier = new BCELifier(outerClass, System.out); 
    fier.start(); 

    final JavaClass outer2Class = Repository.lookupClass(net.madz.lifecycle.solutionOne.ServiceOrder.class.getName()); 
    BCELifier fier2 = new BCELifier(outer2Class, System.out); 
    fier2.start(); 

然後找到差異部:

正確:

il.append(_factory.createFieldAccess("java.lang.Long", "TYPE", new ObjectType("java.lang.Class"), Constants.GETSTATIC)); 

WRONG:

il.append(_factory.createFieldAccess("java.lang.Long", "TYPE", Type.LONG, Constants.GETSTATIC)); 

在我的代碼,其實我使用:

ilist.append(ifact.createGetStatic(convertType2ClassName(type), "TYPE", Type.LONG)); 

顯然,這應該是:

ilist.append(ifact.createGetStatic(convertType2ClassName(type), "TYPE", new ObjectType("java.lang.Class"))); 

總之,有兩個錯誤我犯了:

  1. 我沒有用InstructionFactory.createFieldAccess方法,但我選擇InstructionFactory.createGetStatic,雖然他們可以產生相同的結果,但createFieldAccess有文檔,createGetStatic沒有。
  2. 我應該使用除Type.LONG以外的新ObjectType(Class.class.getName()),因爲它應該是字段類型,它應該與Class []匹配。