ByteBuddy有没有可能用ASM实现一个方法

ByteBuddy is it possible to use ASM to implement a method

是否可以将 bytebuddy 的高级 api 和 asm 的低级 api 结合起来?

我想通过 bytebuddy 生成一个 class、它的字段、注释和一些通用方法,例如 getters setters,因为它比 asm 容易得多。

但是我需要实现一个抽象 class,我需要在其中使用 bytebuddy 似乎不支持的功能,例如条件、分支、在编译时调用另一个参数数量未知的方法等等

我偶然发现 net.bytebuddy.implementation.bytecode.ByteCodeAppender 一个公开 MethodVisitor 的 class,但我找不到任何如何正确使用它的示例。

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(...) 简单地包装 appender。