2014-08-29 14 views
5

Sono nuovo al framework ASM. Ho lavorato su questo framework ASM per una settimana. Ho visto tutorial in rete per quanto riguarda l'analisi di una classe e la generazione di un file .class da zero. Ma non riesco a seguire come modificare una classe esistente in ASM.Come modificare un bytecode Java utilizzando ASM 4.0

Gentilmente aiutatemi.

Non sono in grado di seguire il flusso di esecuzione tra ClassVisitor, ClassWriter e ClassReader.

Gentilmente risolvere il mio problema dandomi un esempio ASM per il seguente codice.

public class ClassName { 


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

public static void main(String[] args) { 

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

} 

} 

La classe sopra dovrebbe essere modificato come:

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(); 

} 

} 

quello che dovrebbe essere il codice ASM per modificarlo?

Ho utilizzato lo strumento ASMifier per generare il codice. Ma non so dove applicarlo.

Per favore aiutatemi. +

+0

@MartinFrank ma voglio creare un nuovo Mwthod e chiamarlo. quello specificato c'era al livello base! – Narayana

+0

Np. Succede anche per me. – icbytes

risposta

6

Le vostre esigenze sono un po 'sottostimate. Di seguito è riportato un programma di esempio che utilizza l'API visitatore di ASM per trasformare una classe che si presuppone abbia la struttura della domanda nella classe risultante. Ho aggiunto un metodo comodo prendendo un array di byte e restituendo un array di byte. Tale metodo può essere utilizzato in entrambi i casi, una trasformazione statica applicata ai file di classe su disco e in un agente di Strumentazione.

Quando si combinano un ClassWriter con un ClassVisitor passato a una ClassReader come sotto, si replicherà automaticamente tutte le funzionalità del classe di origine in modo da avere eseguire l'override solo questi metodi in cui si desidera applicare le modifiche.

Qui, visitMethod è sovrascritto per intercettare quando incontrano il metodo main per modificarla e visitEnd è sovrascritto per aggiungere il tutto nuovo metodo showTwo. Lo MainTransformer intercetterà le istruzioni RETURN (dovrebbe essercene solo una nel tuo esempio) per inserire la chiamata a showTwo prima di essa.

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

Grazie. Ma può spiegare il flusso di questo programma. Dov'è il metodo principale per eseguire questo programma ASM. come genererà la nuova classe. puoi per favore dare il codice completo, signore !! – Narayana

+1

Non esiste un metodo 'main' come non hai specificato nella tua domanda cosa dovrebbe fare il metodo' main'. Ho già affrontato questo all'inizio della mia risposta. Ho fornito un metodo 'static' accettando un array di byte e fornendo un array di byte. Da dove prendi quella matrice e cosa farai con il risultato, dipende da cosa vuoi veramente fare. Non riesco a leggerti nella tua mente. – Holger

+0

Grazie per la cortese risposta. quello che voglio fare è: leggere questo file di classe ed eseguire queste modifiche e generare un altro file di classe con queste modifiche apportate. puoi aiutarmi, signore! – Narayana