2015-02-18 3 views
1

Я пытаюсь изучить java asm framework для инструментария байт-кода, но не смог найти достаточное количество документов или учебников на нем.Я пытаюсь изучить java asm framework для инструментария байт-кода, но не могу найти достаточное количество документов или руководств по нему

Я изучил ClassReader, ClassWriter и ClassVisitor и некоторые более похожие API, но не очень ясно, как их реализовать и как писать соответствующие адаптеры.

Допустим, у меня есть класс Java HelloWorld.

public class HelloWorld { 

    public static void main(String[] args) { 
//some code..... 

    } 

} 

Теперь я хочу вставить переменную «int i = 10;» в байт-коде. Пожалуйста, дайте мне представление о том, что я должен написать Adapter/program.

Заранее благодарен!

+0

http://docs.oracle.com/javase/specs/jvms/se8/html/ – Holger

+0

Читали: HTTP: // скачать .forge.objectweb.org/asm/asm4-guide.pdf? Там есть простые примеры, я считаю, что объясняю, что вы хотите сделать (я читал это некоторое время назад, поэтому я не уверен). – Grzesuav

ответ

4

Ниже приведен способ добавления дополнительных полей к классу, таких как «int i = 10;». Предполагая, что вы используете javaagent для выполнения измерительных приборов: 1) Используйте следующие как класс premain из Java агента

import java.lang.instrument.Instrumentation; 

public class SimpleAgent { 

    public static void premain(String agentArgs, Instrumentation inst) { 

     ClassTransformer transformer = new ClassTransformer(); 
     inst.addTransformer(transformer); 
    } 
} 

2) addTransformer вызывает метод преобразования класса ClassTransformer, который определяется следующим образом

import java.lang.instrument.ClassFileTransformer; 
import java.lang.instrument.IllegalClassFormatException; 
import java.security.ProtectionDomain; 
import org.objectweb.asm.ClassReader; 
import org.objectweb.asm.ClassWriter; 

public class ClassTransformer implements ClassFileTransformer{ 
    public byte[] transform(ClassLoader loader, 
      String    className, 
      Class   classBeingRedefined, 
      ProtectionDomain protectionDomain, 
      byte[]    b) 
        throws IllegalClassFormatException { 
     try 
     { 
       ClassReader cr=new ClassReader(b); 
       ClassWriter cw = new ClassWriter(cr,ClassWriter.COMPUTE_MAXS); 
       AddField cp = new AddField(cw); 
       cr.accept(cp,0); 
       return cw.toByteArray(); 
     } 
     catch(Exception e) 
     { 
      System.out.println(e); 
     } 
     return b; 
    } 
} 

3) наконец AddField, которая выглядит следующим образом является ClassVisitor, который отвечает добавить новое поле в классе

import static org.objectweb.asm.Opcodes.ASM4; 
import org.objectweb.asm.ClassVisitor; 


class AddField extends ClassVisitor{ 

    static String className; 
    static String methName, descrip; 
    public AddField(ClassVisitor cv) { 
     super(ASM4, cv); 
    } 

    @Override 
    public void visit(int version, int access, String name, 
      String signature, String superName, String[] interfaces) { 
     className = name; 
     cv.visit(version, access, name, signature, superName, interfaces); 
    } 
    public void visitEnd() { 
     cv.visitField(0, "i", "I", null , new Integer(10)); 
     cv.visitEnd(); 
    } 
} 

4. ** NEW EDIT ** для добавления переменной в метод. Переменная должна быть сохранена во временную переменную и затем может быть использована позже. После адаптера можно использовать для этой цели (смотрите на onMethodEnter):

import static org.objectweb.asm.Opcodes.ASM4; 
import static org.objectweb.asm.Opcodes.*; 
import org.objectweb.asm.ClassVisitor; 
import org.objectweb.asm.MethodVisitor; 
import org.objectweb.asm.commons.AdviceAdapter; 

public class MethodAdapter extends ClassVisitor { 


    public MethodAdapter(ClassVisitor cv) { 
     super(ASM4, cv); 
    } 

    @Override 
    public void visit(int version, int access, String name, 
      String signature, String superName, String[] interfaces) { 
     cv.visit(version, access, name, signature, superName, interfaces); 
    } 


    public MethodVisitor visitMethod(int access, String name, 
      String desc, String signature, String[] exceptions) { 
     MethodVisitor mv; 
     mv = cv.visitMethod(access, name, desc, signature, exceptions); 
     mv = new AddVariableAdapter(access, name, desc, mv); 
     return mv; 
    } 
    public void visitEnd() { 
     cv.visitEnd(); 
    } 


    public class AddVariableAdapter extends AdviceAdapter{ 
     public AddCallAdapter(int access, String name, String desc, 
       MethodVisitor mv) { 
      super(ASM4, mv, access, name, desc); 
     } 

     protected void onMethodEnter() { 
      mv.visitIntInsn(BIPUSH, 10); // pushes the number 10 on to the stack 
      mv.visitVarInsn(ISTORE, 1); // pops the top of the stack into a local variable indexed by 1 
     /* code to print the local variable 
      mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); 
      mv.visitVarInsn(ILOAD, 1); 
      mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(I)V");*/ 
     } 
    } 
} 
+0

Извините, но я думаю, что это не ответ. Он хотел вставить переменную, а не поле. – Clashsoft

+0

Спасибо за разъяснение. Я добавил адаптер для добавления переменной. – sri91

+0

Спасибо большое –

1

Хороший способ узнать, как использовать ASM, - это запустить инструмент ASMifier. Если вы просто хотите знать, как определенные конструкторы языка, такие как переменные инициализаторы, преобразуются в байт-код, может быть полезно создать простой класс Java, скомпилировать его, найти файл .class и запустить на нем javap или открыть его с помощью IDE.