【问题标题】:ByteBuddy is it possible to use ASM to implement a methodByteBuddy 是否可以使用 ASM 来实现一个方法
【发布时间】:2020-06-13 16:57:47
【问题描述】:

bytebuddy的高级api和asm的低级api可以结合起来吗?

我想通过 bytebuddy 生成一个类、它的字段、注释和一些通用方法,例如 getter 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);
}

【问题讨论】:

    标签: java java-bytecode-asm byte-buddy


    【解决方案1】:

    您的方法是正确的,但您需要使用Implementation 来提供您的ByteCodeAppender。使用MethodDelegation 尝试对对象进行委托,前提是没有任何意义,因为它们没有任何意义的委托目标是什么异常试图告诉您。如果您不进行任何特定调整,您可以使用 new Implementation.Simple(...) 简单地包装 appender。

    【讨论】:

    • 我可以让底层类/方法编写器自动计算堆栈帧大小吗?对于纯 asm,这意味着传递给 ClassWriter.COMPUTE_FRAMES 的 ClassWriter 构造函数值
    • 您可以注册一个ClassVisitorWrapper 并将标志传递给那里的ASM。
    猜你喜欢
    • 2021-08-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多