是否可以将bytebuddy的高级api和asm的低级api结合在一起?
我想通过bytebuddy生成一个类,其字段,注释和一些通用方法,例如getters setter,因为它比asm容易得多。
但是然后我需要实现一个抽象类,在这里我需要使用bytebuddy似乎不支持的功能,例如条件,分支,在编译时调用具有未知数量参数的其他方法等。
我偶然发现net.bytebuddy.implementation.bytecode.ByteCodeAppender
一个公开MethodVisitor的类,但是我找不到任何示例来正确使用它。
new ByteBuddy()
.subclass(Base.class)
.name(className)
... define fields ...
.defineMethod("testFor", Result.class, Ownership.MEMBER, Visibility.PUBLIC) //testFor is an abstract method on superclass that i inherit from - public abstract Result testFor(Context c, WEnvironment env)
.withParameters(Context.class, WEnvironment.class)
.intercept(MethodDelegation.to(new ByteCodeAppenderImpl(...some ctr args...)));
class ByteCodeAppenderImpl implements ByteCodeAppender {
<...ctr...>
@Override
public Size apply(MethodVisitor mv, Implementation.Context implContext, MethodDescription insnMethod) {
mv.visitCode();
mv.visitVarInsn(...);
mv.visitFieldInsn(..)
//Here i do required asm calls to implement the method
....
StackManipulation.Size operandStackSize = new StackManipulation.Compound().apply(methodVisitor, implementationContext);
return new Size(operandStackSize.getMaximalSize(), instrumentedMethod.getStackSize());
}
通过这样做,我得到一个例外:
None of [protected void java.lang.Object.finalize() throws java.lang.Throwable, public final void java.lang.Object.wait() throws java.lang.InterruptedException, public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException, public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException, public boolean java.lang.Object.equals(java.lang.Object), public java.lang.String java.lang.Object.toString(), public native int java.lang.Object.hashCode(), public final native java.lang.Class java.lang.Object.getClass(), protected native java.lang.Object java.lang.Object.clone() throws java.lang.CloneNotSupportedException, public final native void java.lang.Object.notify(), public final native void java.lang.Object.notifyAll(), public net.bytebuddy.implementation.bytecode.ByteCodeAppender$Size my.playground.BytebuddyPlayground08$ByteCodeAppenderImpl .apply(net.bytebuddy.jar.asm.MethodVisitor,net.bytebuddy.implementation.Implementation$Context,net.bytebuddy.description.method.MethodDescription)] allows for delegation from public my.playground.Result my.playground.Custom1592066531191.testFor(my.playground.Context,my.playground.WEnvironment)
java.lang.IllegalArgumentException: None of [protected void java.lang.Object.finalize() throws java.lang.Throwable, public final void java.lang.Object.wait() throws java.lang.InterruptedException, public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException, public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException, public boolean java.lang.Object.equals(java.lang.Object), public java.lang.String java.lang.Object.toString(), public native int java.lang.Object.hashCode(), public final native java.lang.Class java.lang.Object.getClass(), protected native java.lang.Object java.lang.Object.clone() throws java.lang.CloneNotSupportedException, public final native void java.lang.Object.notify(), public final native void java.lang.Object.notifyAll(), public net.bytebuddy.implementation.bytecode.ByteCodeAppender$Size my.playground.BytebuddyPlayground08$ByteCodeAppenderImpl .apply(net.bytebuddy.jar.asm.MethodVisitor,net.bytebuddy.implementation.Implementation$Context,net.bytebuddy.description.method.MethodDescription)] allows for delegation from public my.playground.Result my.playground.Custom1592066531191.testFor(my.playground.Context,my.playground.WEnvironment)
at net.bytebuddy.implementation.bind.MethodDelegationBinder$Processor.bind(MethodDelegationBinder.java:1096)
at net.bytebuddy.implementation.MethodDelegation$Appender.apply(MethodDelegation.java:1282)
at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod$WithBody.applyCode(TypeWriter.java:713)
at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod$WithBody.applyBody(TypeWriter.java:698)
at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod.apply(TypeWriter.java:605)
at net.bytebuddy.dynamic.scaffold.TypeWriter$Default$ForCreation.create(TypeWriter.java:5133)
at net.bytebuddy.dynamic.scaffold.TypeWriter$Default.make(TypeWriter.java:1933)
at net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder.make(SubclassDynamicTypeBuilder.java:225)
at net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder.make(SubclassDynamicTypeBuilder.java:198)
at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase.make(DynamicType.java:3404)
at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase$Delegator.make(DynamicType.java:3600)
我继承的Base.class及其要实现的方法
public abstract class Base<T extends WEnvironment> extends ContextTest {
public abstract Result testFor(Context c, T t);
}
您的方法是正确的,但是您需要使用Implementation
来提供您的ByteCodeAppender
。使用MethodDelegation
尝试委派给该对象,前提是没有意义的对象(因为它们没有意义的委派目标)是异常试图告诉您的内容。如果不进行任何特定的调整,则可以简单地使用new Implementation.Simple(...)
包装附加程序。