2016-03-21 57 views
1

我想改變方法內現有try/catch塊的catch塊的代碼內容。如何使用ASM修改catch塊代碼Bytecode框架

public static void hello(Throwable throwable) { 
    try{ 
     System.out.println("in try"); 
    }catch(Exception e){ 
     System.out.println("in catch"); 
    } 
} 

我的意圖是在catch塊中添加一個方法調用。喜歡的東西,

public static void hello(Throwable throwable) { 
    try{ 
     System.out.println("in Try"); 
    }catch(Exception e){ 
     *passException(e);* 
     System.out.println("in catch"); 
    } 
} 

注:我已經嘗試覆蓋的MethodVisitorvisitTryCatchBlock方法。並嘗試以多種方式訪問​​該標籤,但沒有任何幫助。我無法在網絡上的任何文檔/指南/例子中找到它。我希望我已經清楚地解釋說,在嘗試一切之後,我發佈了這個問題。

+0

當您投票回答此問題時,請至少提出意見。 – AKS

+1

也許有人會因爲你的問題沒有表現出努力來解決問題而自鳴得意。目前看起來你更希望別人做你的工作。通過您迄今爲止所做的代碼,並明確您的問題在哪裏。 – SubOptimal

+1

這是我沒有其他選擇的地方。如果有其他選擇是開放的,沒有人願意來到這裏,並努力提出詳細的問題。可能是我應該把我探索之前來到這裏的選項。 – AKS

回答

0

如果您在ASM中使用Tree API,您可以獲取該類的MethodNode,然後獲取MethodNode的指令(InsnList)。使用InsnList的toArray()方法,您可以遍歷各個指令。要編輯指令,你應該這樣做:

for (MethodNode method : classNode.methods) { 
    method.instructions.set(insn, otherInsn); // Sets the instruction to another one 
    method.instructions.remove(insn); //Removes a given instruction 
    method.instructions.add(insn); //Appends to end 
    method.instructions.insert(insn, otherInsn); // Inserts an instruction after the given insn 
    method.instructions.insertBefore(insn, otherInsn); // Inserts an instruction before the given insn 
} 

我個人覺得這是編輯方法體的最簡單的方法。

0

目前尚不清楚您所面臨的實際障礙是您的企圖描述是否指向正確的方向visitTryCatchBlockvisitLabel。這裏是一個自包含的例子做這項工作:

import java.io.IOException; 
import java.lang.reflect.Method; 

import org.objectweb.asm.*; 

public class EnhanceExceptionHandler { 
    static class Victim { 
     public static void hello(boolean doThrow) { 
      try { 
       System.out.println("in try"); 
       if(doThrow) { 
        throw new Exception("just for demonstration"); 
       } 
      } catch(Exception e){ 
       System.out.println("in catch"); 
      } 
     } 
     static void passException(Exception e) { 
      System.out.println("passException(): "+e); 
     } 
    } 

    public static void main(String[] args) 
     throws IOException, ReflectiveOperationException { 

     Class<EnhanceExceptionHandler> outer = EnhanceExceptionHandler.class; 
     ClassReader classReader=new ClassReader(
      outer.getResourceAsStream("EnhanceExceptionHandler$Victim.class")); 
     ClassWriter classWriter=new ClassWriter(classReader,ClassWriter.COMPUTE_FRAMES); 
     classReader.accept(new ClassVisitor(Opcodes.ASM5, classWriter) { 
      private String className; 

      @Override 
      public void visit(int version, int access, String name, String signature, 
       String superName, String[] interfaces) { 

       className=name; 
       super.visit(version, access, name, signature, superName, interfaces); 
      } 

      @Override 
      public MethodVisitor visitMethod(int access, String name, String desc, 
       String signature, String[] exceptions) { 

       MethodVisitor visitor 
        = super.visitMethod(access, name, desc, signature, exceptions); 
       if(name.equals("hello")) { 
        visitor=new MethodVisitor(Opcodes.ASM5, visitor) { 
         Label exceptionHandler; 

         @Override 
         public void visitLabel(Label label) { 
          super.visitLabel(label); 
          if(label==exceptionHandler) { 
           super.visitInsn(Opcodes.DUP); 
           super.visitMethodInsn(Opcodes.INVOKESTATIC, className, 
            "passException", "(Ljava/lang/Exception;)V", false); 
          } 
         } 

         @Override 
         public void visitTryCatchBlock(
          Label start, Label end, Label handler, String type) { 

          exceptionHandler=handler; 
          super.visitTryCatchBlock(start, end, handler, type); 
         } 
        }; 
       } 
       return visitor; 
      } 
     }, ClassReader.SKIP_FRAMES|ClassReader.SKIP_DEBUG); 

     byte[] code=classWriter.toByteArray(); 
     Method def=ClassLoader.class.getDeclaredMethod(
      "defineClass", String.class, byte[].class, int.class, int.class); 
     def.setAccessible(true); 
     Class<?> instrumented=(Class<?>)def.invoke(
      outer.getClassLoader(), outer.getName()+"$Victim", code, 0, code.length); 
     Method hello=instrumented.getMethod("hello", boolean.class); 
     System.out.println("invoking "+hello+" with false"); 
     hello.invoke(null, false); 
     System.out.println("invoking "+hello+" with true"); 
     hello.invoke(null, true); 
    } 
} 

正如你所看到的,它是直接的,只是記錄異常處理程序的標籤在visitTryCatchBlock和遇到的visitLabel代碼位置後立即注入所需的代碼。其餘的是讀取和轉換類文件並加載測試結果的批量代碼。

+0

非常感謝!我會嘗試一下並讓你知道更新。我如何掌握使用ASM注入代碼。我的意思是這只是繼續嘗試這些事情,或者有一些適當的指導或文件。 – AKS

+0

您是否嘗試過http://asm.ow2.org/的內容? – Holger