2016-03-21 2 views
1

Я пытаюсь изменить содержимое кода блока catch существующего блока try/catch внутри метода.Как изменить код блока catch с использованием структуры ASM 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"); 
    } 
} 

Примечание: я уже пытался переопределить visitTryCatchBlock метод MethodVisitor. И экспериментировал с посещением лейбла разными способами, но ничего не помогло. Я не могу найти это в любой документации/руководстве/примерах в сети. Надеюсь, я ясно объяснил, что я задаю этот вопрос, пробовав все.

+0

Пожалуйста, по крайней мере, оставьте комментарий, когда вы не голосовали на этот вопрос. – AKS

+1

Возможно, кто-то занижает, потому что ваш вопрос не показывает никаких усилий, чтобы решить проблему самостоятельно. В настоящее время выглядит больше, и вы хотите, чтобы кто-то другой выполнял вашу работу. Прошлый код, который вы сделали до сих пор, и уточните, где ваша проблема. – SubOptimal

+1

Это место, где я прихожу, когда у меня нет другого выбора. Никто не хотел бы приезжать сюда и приложить усилия, чтобы задать подробный вопрос, если будут открыты другие варианты. Может быть, я должен поместить варианты, которые я изучил, прежде чем приходить сюда. – AKS

ответ

0

Если вы используете API дерева в ASM, вы можете получить MethodNode класса, а затем инструкции MethodNode (InsnList). Используя метод InsArlist InString(), вы можете выполнять итерацию по отдельным инструкциям. Чтобы отредактировать инструкции, вы сделали бы что-то вроде этого:

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

Непонятно, к какому фактическому препятствию вы столкнулись, так как ваше описание ваших попыток указывает на правильное направление, visitTryCatchBlock и visitLabel. Вот самодостаточный пример, который делает работу:

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