2014-08-29 12 views
5

Neu im ASM-Framework. Ich arbeite seit einer Woche an diesem ASM-Framework. Ich habe Tutorials im Netz gesehen, wie man eine Klasse analysiert und eine .class-Datei von Grund auf neu erstellt. Aber ich kann nicht folgen, wie man eine vorhandene Klasse in ASM ändert.So ändern Sie einen Java-Bytecode mit ASM 4.0

Bitte helfen Sie mir.

Ich bin nicht in der Lage, den Ablauf der Ausführung zwischen dem ClassVisitor, ClassWriter und ClassReader zu folgen.

Bitte lösen Sie mein Problem, indem Sie mir ein ASM-Beispiel für den folgenden Code geben.

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

} 

} 

Was sollte der ASM-Code, es zu ändern sein:

public class ClassName { 


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

public static void main(String[] args) { 

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

} 

} 

Die obige Klasse sollte so geändert werden?

Ich habe das ASMifier-Tool verwendet, um den Code zu generieren. Aber ich weiß nicht, wo ich es anwenden soll.

Bitte helfen Sie mir. +

+0

@MartinFrank aber ich möchte ein neues Mwthod erstellen und es anrufen. der dort angegebene war auf einer grundlegenden Ebene! – Narayana

+0

Nr. Passiert auch für mich. – icbytes

Antwort

6

Ihre Anforderungen sind etwas unterspezifiziert. Unten finden Sie ein Beispielprogramm, das die Besucher-API von ASM zum Transformieren einer Klasse verwendet, von der angenommen wird, dass sie die Struktur Ihrer Frage in der resultierenden Klasse hat. Ich fügte eine Bequemlichkeitsmethode hinzu, die ein Bytearray und ein Bytearray zurücknimmt. Eine solche Methode kann in beiden Fällen verwendet werden, eine statische Transformation, die auf Klassendateien auf der Festplatte sowie in einem Instrumentation-Agenten angewendet wird.

Wenn ein ClassWriter mit einem ClassVisitor zu einem ClassReader wie unten geführt kombiniert, wird es automatisch jedes Merkmal der Quellklasse replizieren, so dass Sie nur diese Methoden außer Kraft setzen müssen, wo Sie Änderungen anwenden möchten.

Hier visitMethod ist außer Kraft gesetzt abzufangen, wenn die main Verfahren zu begegnen, ihn zu ändern und visitEnd ist außer Kraft gesetzt, die völlig neue Methode showTwo anzuhängen. Die MainTransformer wird RETURN Anweisungen abfangen (es sollte nur eine in Ihrem Beispiel sein), um den Anruf an showTwo davor einzufügen.

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

Danke. Aber bitte erläutern Sie den Ablauf dieses Programms. Wo ist die Hauptmethode zum Ausführen dieses ASM-Programms? wie es die neue Klasse generiert. Kannst du bitte den vollständigen Code sir !! – Narayana

+1

Es gibt keine 'main'-Methode, da Sie in Ihrer Frage nicht angegeben haben, was diese' main'-Methode tun soll. Ich habe dies bereits am Anfang meiner Antwort angesprochen. Ich habe eine "statische" Methode zur Verfügung gestellt, die ein Byte-Array akzeptiert und ein Byte-Array bereitstellt. Woher du dieses Array bekommst und was du mit dem Ergebnis machen wirst, hängt davon ab, was du wirklich machen willst. Ich kann deine Gedanken nicht lesen. – Holger

+0

Danke für Ihre freundliche Antwort. Was ich tun möchte, ist: Lesen Sie diese Klassendatei und führen Sie diese Änderungen durch und generieren Sie eine andere Klassendatei mit diesen vorgenommenen Änderungen. kannst du mir helfen, mein Herr! – Narayana