预期目标
假如有一个HelloWorld
类,代码如下:
public class HelloWorld {
public int intValue;
public String strValue;
}
我们想实现的预期目标:为HelloWorld
类添加Object objValue
字段。
编码实现
实现步骤:
- 第一步,在
visitField()
方法中,判断该字段是否已经存在。 - 第二步,在
visitEnd()
方法中,如果该字段不存在,则进行添加;如果该字段已经存在,则不进行任何操作。
进一步验证:在进行转换的时候,我们可以测试一下是否会添加重复的字段。
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
public class ClassAddFieldVisitor extends ClassVisitor {
private final int fieldAccess;
private final String fieldName;
private final String fieldDesc;
private boolean isFieldPresent;
public ClassAddFieldVisitor(int api, ClassVisitor classVisitor, int fieldAccess, String fieldName, String fieldDesc) {
super(api, classVisitor);
this.fieldAccess = fieldAccess;
this.fieldName = fieldName;
this.fieldDesc = fieldDesc;
}
@Override
public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
if (name.equals(fieldName)) {
isFieldPresent = true;
}
return super.visitField(access, name, descriptor, signature, value);
}
@Override
public void visitEnd() {
if (!isFieldPresent) {
FieldVisitor fv = cv.visitField(fieldAccess, fieldName, fieldDesc, null, null);
if (fv != null) {
fv.visitEnd();
}
}
super.visitEnd();
}
}
进行转换
import lsieun.utils.FileUtils;
import org.objectweb.asm.*;
public class HelloWorldTransformCore {
public static void main(String[] args) {
String relative_path = "sample/HelloWorld.class";
String filepath = FileUtils.getFilePath(relative_path);
byte[] bytes1 = FileUtils.readBytes(filepath);
//(1)构建ClassReader
ClassReader cr = new ClassReader(bytes1);
//(2)构建ClassWriter
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
//(3)串连ClassVisitor
int api = Opcodes.ASM9;
ClassVisitor cv = new ClassAddFieldVisitor(api, cw, Opcodes.ACC_PUBLIC, "objValue", "Ljava/lang/Object;");
//(4)结合ClassReader和ClassVisitor
int parsingOptions = ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES;
cr.accept(cv, parsingOptions);
//(5)生成byte[]
byte[] bytes2 = cw.toByteArray();
FileUtils.writeBytes(filepath, bytes2);
}
}