2015-03-02 3 views
1

Так, с кодом, написанным ниже, мой вывод:Java байткод приборы с использованием ASM, MethodVisitor является нулевым

Starting application with the Agent 
Visiting class: HelloWorld 
Class Major Version: 51 
Super class: java/lang/Object 
Source: HelloWorld.java 
Method: <init> desc =()V cv = [email protected] and mv = null 
Method: main desc = ([Ljava/lang/String;)V cv = [email protected] and mv = null 
Method: foo desc =()V cv = [email protected] and mv = null 
Method ends here 
Done instrumenting: HelloWorld 

который озадачивает меня. Почему мой methodVisitor будет null? Исходный код ASM, по-видимому, возвращает null для methodVisitor, когда classVisitor - null, что в нашем случае неверно.

package com.amir.agent.instrumentor; 

import org.objectweb.asm.AnnotationVisitor; 
import org.objectweb.asm.Attribute; 
import org.objectweb.asm.ClassReader; 
import org.objectweb.asm.ClassVisitor; 
import org.objectweb.asm.FieldVisitor; 
import org.objectweb.asm.MethodVisitor; 
import org.objectweb.asm.Opcodes; 

public class amirClassVisitor { 

    private byte[] outData = null; 

    public amirClassVisitor() { 
    } 

    public void performInstrumentation(final String className, 
             final byte[] classAsBytes) { 
     final ClassVisitor cl = new ClassVisitor(Opcodes.ASM4) { 
      @Override 
      public void visit(final int version, 
           final int access, 
           final String name, 
           final String signature, 
           final String superName, 
           final String[] interfaces) { 
       System.out.println("Visiting class: "+name); 
       System.out.println("Class Major Version: "+version); 
       System.out.println("Super class: " + superName); 
       super.visit(version, access, name, signature, superName, interfaces); 
      } 

      @Override 
      public void visitOuterClass(final String owner, 
             final String name, 
             final String desc) { 
       System.out.println("Outer class: "+owner); 
       super.visitOuterClass(owner, name, desc); 
      } 

      @Override 
      public AnnotationVisitor visitAnnotation(final String desc, 
                final boolean visible) { 
       System.out.println("Annotation: "+desc); 
       return super.visitAnnotation(desc, visible); 
      } 

      @Override 
      public void visitAttribute(final Attribute attr) { 
       System.out.println("Class Attribute: " + attr.type); 
       super.visitAttribute(attr); 
      } 

      @Override 
      public void visitInnerClass(final String name, 
             final String outerName, 
             final String innerName, 
             final int access) { 
       System.out.println("Inner Class: " + innerName + " defined in " + outerName); 
       super.visitInnerClass(name, outerName, innerName, access); 
      } 

      @Override 
      public FieldVisitor visitField(final int access, 
              final String name, 
              final String desc, 
              final String signature, 
              final Object value) { 
       System.out.println("Field: "+name+" "+desc+" value:"+value); 
       return super.visitField(access, name, desc, signature, value); 
      } 

      @Override 
      public void visitEnd() { 
       System.out.println("Method ends here"); 
       super.visitEnd(); 
      } 

      @Override 
      public MethodVisitor visitMethod(final int access, 
              final String name, 
              final String desc, 
              final String signature, 
              final String[] exceptions) { 
       final MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); 
       System.out.println("Method: " +name+ " desc = " +desc+ " cv = " +this+ " and mv = " +mv); 
       return mv; 
      } 

      @Override 
      public void visitSource(final String source, 
            final String debug) { 
       System.out.println("Source: "+source); 
       super.visitSource(source, debug); 
      } 

     }; 

     final ClassReader classReader = new ClassReader(classAsBytes); 
     classReader.accept(cl, 0); 
     System.out.println("Done instrumenting: " +className); 

    } 

    public byte[] result() { 
     return outData; 
    } 

} 

EDIT:

Я называю этот код так:

public class ClassLoadInterceptor implements ClassFileTransformer { 

    @SuppressWarnings("unchecked") 
    public byte[] transform(final java.lang.ClassLoader loader, 
          final java.lang.String className, 
          final java.lang.Class classBeingRedefined, 
          final java.security.ProtectionDomain protectionDomain, 
          final byte[] classfileBuffer) throws IllegalClassFormatException { 

     if (!(className.startsWith("java") || className.startsWith("sun") || className.startsWith("com/workday/agent"))) { 
      WorkdayClassVisitor v = new WorkdayClassVisitor(); 
      v.performInstrumentation(className, classfileBuffer); 
      System.out.println("\t Instrumenting : " +className); 
      byte[] instrumented_class = v.result(); 
      writeOutClassFile("debug", className + ".class", classfileBuffer); 
      writeOutClassFile("debug", className + "_instrumented" + ".class", instrumented_class); 
      return instrumented_class; 
     } 

     return classfileBuffer; 

    } 
+0

Как вы называете метод? –

ответ

1

Что распечатке не «мой methodVisitor», но значение, возвращаемое super вызовом visitMethod, в другом слова значение по умолчанию, возвращаемое ClassVisitor.visitMethod:

Возвращает:
объект для посещения байтового кода метода, или null, если этот посетитель этого класса не заинтересован в просмотре кода этого метода.

Поскольку абстрактный класс ClassVisitor не выполняет никаких действий, она не имеет никакого интереса к посещению метода и поэтому null является идеальным возвращаемым значением.

Так что вам решать, создать новый MethodVisitor, реализуя желаемое поведение. Или, поскольку вы, похоже, намереваетесь использовать класс, пусть ваш посетитель вашего класса отправит ClassWriter, который вы перейдете на super class constructor. Таким образом, вы наследуете поведение репликации, которое вы можете настроить. Затем super.visitMethod вернет посетителя метода не null, который будет реплицировать метод.

+0

Благодарим вас за ответ. Чтобы подтвердить, что вы сказали, я создал новый MethodVisitor и, похоже, делает то, что вы говорите точно. То, что я до сих пор не понимаю, - это роль ClassWriter. Можете ли вы продемонстрировать, как это будет вписываться в код, который я вставил выше? –

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