2016-03-21 27 views
1

メソッド内の既存のtry/catchブロックのキャッチブロックのコードの内容を変更しようとしています。ASMを使用してキャッチブロックコードを変更する方法バイトコードフレームワーク

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

多分あなたの質問があなた自身で問題を解決する努力を示していないので、誰かがdownvote。現在、他の人が仕事をしたいと思っています。これまでに行ったコードを遡って、問題がどこにあるかを明確にしてください。 – SubOptimal

+1

これは私が他のオプションを持っていないときに来る場所です。誰もここに来て、他のオプションが開いていれば詳細な質問をするのをやめようとは思わない。私はここに来る前に私が調べたオプションを置くべきかもしれない。 – AKS

答えて

0

ASMでツリー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

関連する問題