2014-08-29 60 views
5

是ASM框架的新手。我一直在爲這個ASM框架工作一週。我在網上看到了有關解析類和從頭開始生成.class文件的教程。 但我無法按照如何修改ASM中的現有類。如何使用ASM 4.0修改Java字節碼

請幫助我。

我無法遵循ClassVisitor,ClassWriter和ClassReader之間的執行流程。

請通過爲我提供以下代碼的ASM示例來解決我的問題。

public class ClassName { 


public void showOne() 
{ 
    System.out.println("Show One Method"); 
} 

public static void main(String[] args) { 

    ClassName c=new ClassName(); 
    c.showOne(); 

} 

} 

上面的類應修改爲:

public class ClassName { 


public void showOne() 
{ 
    System.out.println("Show One Method"); 
} 


public void showTwo() 
{ 
    System.out.println("Show Two Method"); 
} 

public static void main(String[] args) { 

    ClassName c=new ClassName(); 
    c.showOne(); 
    c.showTwo(); 

} 

} 

應該是什麼ASM代碼來修改呢?

我使用了ASMifier工具來生成代碼。但我不知道在哪裏應用它。

請幫幫我。 +

+0

@MartinFrank但我想創建一個新的mwthod並調用它。那裏指定的那個在基本水平! – Narayana 2014-08-29 05:37:12

+0

Np。我也會發生。 – icbytes 2014-08-29 07:52:20

回答

6

您的要求有點低估。下面是一個示例程序,它使用ASM的訪客API將假設爲具有問題結構的類轉換爲生成的類。我添加了一個方便的方法,接受一個字節數組並返回一個字節數組。在這兩種情況下都可以使用這種方法,即對磁盤上的類文件以及Instrumentation代理應用靜態轉換。

當結合了傳遞給ClassReader如下一個ClassVisitor一個ClassWriter,所以你必須只覆蓋要更改應用這些方法會自動複製源類的所有功能。

這裏,visitMethod被重寫遇到main方法時修改它並visitEnd是重寫,以追加全新showTwo方法進行攔截。 MainTransformer將攔截RETURN指令(在您的示例中應該只有一條),以便將呼叫插入到之前的showTwo

import org.objectweb.asm.*; 
import org.objectweb.asm.commons.GeneratorAdapter; 

public class MyTransformer extends ClassVisitor { 

    public static byte[] transform(byte[] b) { 
    final ClassReader classReader = new ClassReader(b); 
    final ClassWriter cw = new ClassWriter(classReader, 
     ClassWriter.COMPUTE_FRAMES|ClassWriter.COMPUTE_MAXS); 
    classReader.accept(new MyTransformer(cw), ClassReader.EXPAND_FRAMES); 
    return cw.toByteArray(); 
    } 

    public MyTransformer(ClassVisitor cv) { 
    super(Opcodes.ASM5, cv); 
    } 
    @Override 
    public MethodVisitor visitMethod(int access, String name, String desc, 
     String signature, String[] exceptions) { 

    MethodVisitor v=super.visitMethod(access, name, desc, signature, exceptions); 
    if(name.equals("main") && desc.equals("([Ljava/lang/String;)V")) 
     v=new MainTransformer(v, access, name, desc, signature, exceptions); 
    return v; 
    } 
    @Override 
    public void visitEnd() { 
    appendShowTwo(); 
    super.visitEnd(); 
    } 
    private void appendShowTwo() { 
    final MethodVisitor defVisitor = super.visitMethod(
     Opcodes.ACC_PUBLIC, "showTwo", "()V", null, null); 
    defVisitor.visitCode(); 
    defVisitor.visitFieldInsn(Opcodes.GETSTATIC, 
     "java/lang/System", "out", "Ljava/io/PrintStream;"); 
    defVisitor.visitLdcInsn("Show Two Method"); 
    defVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, 
     "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false); 
    defVisitor.visitInsn(Opcodes.RETURN); 
    defVisitor.visitMaxs(0, 0); 
    defVisitor.visitEnd(); 
    } 
    class MainTransformer extends GeneratorAdapter 
    { 
    MainTransformer(MethodVisitor delegate, int access, String name, String desc, 
     String signature, String[] exceptions) { 
     super(Opcodes.ASM5, delegate, access, name, desc); 
    } 
    @Override 
    public void visitInsn(int opcode) { 
     if(opcode==Opcodes.RETURN) { 
     // before return insert c.showTwo(); 
     super.visitVarInsn(Opcodes.ALOAD, 1); // variable c 
     super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, 
      "ClassName", "showTwo", "()V", false); 
     } 
     super.visitInsn(opcode); 
    } 
    } 
} 
+0

謝謝。但是可以請說明這個程序的流程。執行此ASM程序的主要方法在哪裏?它將如何產生新的課程。你可以給你完整的代碼先生! – Narayana 2014-08-29 12:58:48

+1

沒有'main'方法,因爲你沒有在你的問題中指定'main'方法應該做什麼。我在回答開始時已經談到了這一點。我提供了一個'static'方法來接受一個字節數組並提供一個字節數組。從哪裏獲得該數組,以及您將如何處理結果,這取決於您真正想要做什麼。我無法讀懂你的想法。 – Holger 2014-08-29 13:10:01

+0

謝謝你的回覆。我想要做的是:讀取此類文件並執行這些更改並生成具有這些更改的另一個類文件。你可以幫我先生! – Narayana 2014-08-29 13:13:47