下面列出了怎么用org.objectweb.asm.ClassAdapter的API类实例代码及写法,或者点击链接到github查看源代码。
@Test
public void ModifyClassTest() throws Exception {
// 读取的Person类的class文件
ClassReader classReader = new ClassReader("org.javamaster.b2c.bytecode.model.Person");
ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS);
ClassAdapter classAdapter = new ClassAdapter(classWriter);
classReader.accept(classAdapter, ClassReader.SKIP_DEBUG);
// 插入新方法
// Opcodes.ACC_PUBLIC:方法修饰符为public
// sayHello:方法名为sayHello
// ()V:没有入参,返回类型为void
// new String[]{"javax.validation.ValidationException"}:声明抛出ValidationException异常
MethodVisitor helloVisitor = classWriter
.visitMethod(Opcodes.ACC_PUBLIC, "sayHello", "()V", null, new String[]{"javax.validation.ValidationException"});
// 插入方法体内容,以下涉及到了虚拟机字节码指令
helloVisitor.visitCode();
// getstatic 指令:取静态字段
helloVisitor.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
// ldc 指令:取"hello world!"常量到操作数栈
helloVisitor.visitLdcInsn("hello world!");
// invokevirtual 指令: 调用实例方法println
helloVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");
// return 指令: 从当前方法返回void
helloVisitor.visitInsn(Opcodes.RETURN);
helloVisitor.visitMaxs(1, 1);
helloVisitor.visitEnd();
byte[] bytes = classWriter.toByteArray();
String path = ResourceUtils.getFile("classpath:").getAbsolutePath();
File file = new File(path, "/org/javamaster/b2c/bytecode/PersonModify.class");
FileOutputStream fileOutputStream = new FileOutputStream(file);
fileOutputStream.write(bytes);
fileOutputStream.close();
}
public byte[] patch(String className, byte[] classBytes) {
if(wrappers.size() == 0) {
return classBytes;
}
matchProps.put(PROP_CLASSNAME, className);
if(patchesFilter != null) {
boolean b = patchesFilter.match(matchProps);
if(!b) {
return classBytes;
}
}
try {
ClassReader cr = new ClassReader(classBytes);
ClassWriter cw = new BundleClassWriter(ClassWriter.COMPUTE_MAXS,
patchedBundle.adapt(BundleWiring.class).getClassLoader());
ClassAdapter trans = new ClassAdapterPatcher(cw,
className.replace('.', '/'),
patchedBundle.adapt(BundleWiring.class).getClassLoader(),
patchedBundle.getBundleId(),
this);
cr.accept(trans, 0);
byte[] newBytes = cw.toByteArray();
if(bDumpClasses) {
dumpClassBytes(className, newBytes);
}
classBytes = newBytes;
} catch (Exception e) {
throw new RuntimeException("Failed to patch " + className + "/"
+ patchedBundle.adapt(BundleWiring.class).getClassLoader() +": " +e);
}
return classBytes;
}
byte[] nullAdaptClass(final InputStream is, final String name)
throws Exception
{
ClassReader cr = new ClassReader(is);
ClassWriter cw = new ClassWriter(compute);
ClassAdapter ca = new ClassAdapter(cw);
cr.accept(ca, skipDebug);
return cw.toByteArray();
}
byte[] counterAdaptClass(final InputStream is, final String name)
throws Exception
{
ClassReader cr = new ClassReader(is);
ClassWriter cw = new ClassWriter(false);
ClassAdapter ca = new CounterClassAdapter(cw);
cr.accept(ca, false);
return cw.toByteArray();
}