2014-08-29 2 views
5

Являясь новым для рамки ASM. Я работаю над этой структурой ASM в течение недели. Я видел учебные пособия в сети, касающиеся разбора класса и создания файла .class с нуля. Но я не могу следить за тем, как изменить существующий класс в ASM.Как изменить байт-код Java с использованием ASM 4.0

Пожалуйста, помогите мне.

Я не могу следить за потоком выполнения между 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

+0

Np. Случается и для меня. – icbytes

ответ

6

Ваши требования немного не указаны. Ниже приведен пример программы, в которой API-интерфейс посетителя ASM используется для преобразования класса, предположительно имеющего структуру вашего вопроса, к результирующему классу. Я добавил метод удобства, принимающий байтовый массив и возвращающий массив байтов. Такой метод может использоваться в обоих случаях, статическое преобразование, применяемое к файлам классов на диске, а также в агенте Instrumentation.

При комбинируя ClassWriter с ClassVisitor прошел в ClassReader, как показано ниже, он будет автоматически реплицировать все функции исходного класса, так что вы должны переопределить только эти методы, где вы хотите, чтобы применить изменения.

Здесь 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

+1

Не существует метода 'main', так как вы не указали в своем вопросе, что должен сделать этот метод' main'. Я уже обращался к этому в начале моего ответа. Я предоставил метод 'static', принимающий байтовый массив и предоставляющий массив байтов. Где вы получаете этот массив и что вы будете делать с результатом, это зависит от того, что вы действительно хотите сделать. Я не могу читать ваши мысли. – Holger

+0

Спасибо за ваш добрый ответ. что я хочу сделать: прочитайте этот файл класса и выполните эти изменения и сгенерируйте другой файл класса с этими внесенными изменениями. может у плз помочь мне сэр! – Narayana

Смежные вопросы