[英]Java bytecode instrumentation using ASM, MethodVisitor is null
So, with the code written below, my output is: 因此,使用下面的代码,我的输出是:
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 = com.amir.agent.instrumentor.amirClassVisitor$1@79f1d448 and mv = null
Method: main desc = ([Ljava/lang/String;)V cv = com.amir.agent.instrumentor.amirClassVisitor$1@79f1d448 and mv = null
Method: foo desc = ()V cv = com.amir.agent.instrumentor.amirClassVisitor$1@79f1d448 and mv = null
Method ends here
Done instrumenting: HelloWorld
which is puzzling me. 这让我感到困惑。 Why would my methodVisitor
be null
? 为什么我的methodVisitor
为null
? The ASM source code seems to only return null
for the methodVisitor
when the classVisitor
is null
, which is not true in my case. 当classVisitor
为null
,ASM源代码似乎仅对methodVisitor
返回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: 编辑:
I call this code like this: 我将这样的代码称为:
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;
}
What you print out is not “my methodVisitor
” but the value returned by the super
invocation of visitMethod
, in other words the default value returned by ClassVisitor.visitMethod
: 你打印出来是不是“我的methodVisitor
”,但被返回的值super
的调用visitMethod
,换句话说返回的默认值ClassVisitor.visitMethod
:
Returns : 返回值 :
an object to visit the byte code of the method, ornull
if this class visitor is not interested in visiting the code of this method. 一个对象,用于访问方法的字节码;如果该类访问者对访问此方法的代码不感兴趣,则返回null
。
Since the abstract class ClassVisitor
does not implement any action, it has no interest in visiting the method and therefore null
is the perfect return value. 由于抽象类ClassVisitor
不执行任何操作,因此对访问该方法没有兴趣,因此null
是理想的返回值。
So it's up to you, to instantiate a new MethodVisitor
implementing your desired behavior. 因此,由您决定实例化一个新的MethodVisitor
实现所需的行为。 Or, since you seem to intend to instrument a class, let your class visitor delegate to a ClassWriter
which you pass to the super class constructor . 或者,由于您似乎打算插入一个类,因此让您的类访问者委托给您传递给超类构造函数的ClassWriter
。 This way you will inherit a replication behavior that you can customize. 这样,您将继承可以自定义的复制行为。 Then, super.visitMethod
will return a non- null
method visitor, which will replicate the method. 然后, super.visitMethod
将返回一个非null
方法访问者,该访问者将复制该方法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.