简体   繁体   中英

add behavior to method with ByteBuddy

Given Sample.someMethod(...) and InvocationHandler decoration , I want to create a dynamic subclass that overrides someMethod with

someMethod(...) {
  decoration.invoke(...);
  super.someMethod(...);
}

My code looks like this:

    Class<? extends Sample> dynamicSubclass = new ByteBuddy()
        .subclass(Sample.class)
        .method(ElementMatchers.named("someMethod"))
            .intercept(new Implementation.Compound(
                InvocationHandlerAdapter.of(decoration),
                SuperMethodCall.INSTANCE))
        .make()
        .load(Sample.class.getClassLoader())  // line 42
        .getLoaded();

...and it results in the following exception:

java.lang.VerifyError: Expecting a stack map frame
Exception Details:
  Location:
    pl/morgwai/sample/pojo/ByteBuddySample$Sample$ByteBuddy$PXUw8Sz7.someMethod(I)Ljava/lang/String; @27: aload_0
  Reason:
    Error exists in the bytecode
  Bytecode:
    0000000: b200 0a2a b200 0e04 bd00 1059 031b b800
    0000010: 1653 b900 1c04 00c0 001e b02a 1bb7 0020
    0000020: b0                                     

    at java.base/java.lang.Class.getDeclaredFields0(Native Method)
    at java.base/java.lang.Class.privateGetDeclaredFields(Class.java:3061)
    at java.base/java.lang.Class.getDeclaredField(Class.java:2409)
    at net.bytebuddy.implementation.LoadedTypeInitializer$ForStaticField.onLoad(LoadedTypeInitializer.java:122)
    at net.bytebuddy.implementation.LoadedTypeInitializer$Compound.onLoad(LoadedTypeInitializer.java:192)
    at net.bytebuddy.dynamic.TypeResolutionStrategy$Passive.initialize(TypeResolutionStrategy.java:102)
    at net.bytebuddy.dynamic.DynamicType$Default$Unloaded.load(DynamicType.java:6292)
    at net.bytebuddy.dynamic.DynamicType$Default$Unloaded.load(DynamicType.java:6281)
    at pl.morgwai.sample.pojo.ByteBuddySample.main(ByteBuddySample.java:42)

What am I doing wrong and how to fix it?
(I'm using byte-buddy 1.10.22 and openjdk-11)

Thanks!

UPDATE:

I'm able to achieve

someMethod(...) {
  decoration.invoke(...);
}

and

someMethod(...) {
  super.someMethod(...);
}

by doing .intercept(InvocationHandlerAdapter.of(decoration)) and .intercept(SuperMethodCall.INSTANCE) respectively, so it seems, I'm not using Implementation.Compound properly...

UPDATE-2:

I'm also able to achieve

someMethod(...) {
  super.someMethod(...);
  decoration.invoke(...);
}

by

.intercept(SuperMethodCall.INSTANCE.andThen(InvocationHandlerAdapter.of(decoration)))

but I can't do the other way around to achieve the order I need as InvocationHandlerAdapter does not implement Implementation.Composable ...

As kindly explained by Rafael Winterhalter it's an unintended omission and in the next release InvocationHandlerAdapter will be implementing Composable ( commit already pushed) and then the simplest way will be to do

.intercept(InvocationHandlerAdapter.of(decoration).andThen(SuperMethodCall.INSTANCE))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM