Intercepting default constructor with Byte Buddy

会有一股神秘感。 提交于 2019-12-10 18:23:36

问题


I'm trying to intercept constructor calls with Byte Buddy, this is my sample code:

package t;

import static net.bytebuddy.dynamic.loading.ClassLoadingStrategy.Default.INJECTION;
import static net.bytebuddy.implementation.MethodDelegation.to;
import static net.bytebuddy.matcher.ElementMatchers.any;
import java.util.concurrent.Callable;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.implementation.bind.annotation.SuperCall;

public class Bar {
  public static void main (String[] args) {
    new ByteBuddy ().subclass (Object.class)
      .name ("t.Foo").constructor (any ()).intercept (to (new Object () {

        @RuntimeType
        public Object construct (@SuperCall Callable<Object> z) throws Exception {
          System.out.println ("CALLING XTOR");
          return z.call ();
        }
      })).make ().load (Bar.class.getClassLoader (), INJECTION).getLoaded ();
  }
}

Which yields the following exception:

Exception in thread "main" java.lang.IllegalStateException: Error invoking java.lang.ClassLoader#findClass
  at net.bytebuddy.dynamic.loading.ClassInjector$UsingReflection$Dispatcher$Resolved.loadClass(ClassInjector.java:392)
  at net.bytebuddy.dynamic.loading.ClassInjector$UsingReflection.inject(ClassInjector.java:201)
  at net.bytebuddy.dynamic.loading.ClassLoadingStrategy$Default$InjectionDispatcher.load(ClassLoadingStrategy.java:199)
  at net.bytebuddy.dynamic.loading.ClassLoadingStrategy$Default.load(ClassLoadingStrategy.java:114)
  at net.bytebuddy.dynamic.DynamicType$Default$Unloaded.load(DynamicType.java:3302)
  at t.Bar.main(Bar.java:21)
Caused by: java.lang.ClassFormatError: Bad method name at constant pool index 19 in class file t/Foo$auxiliary$EalKkAhD
  at java.lang.ClassLoader.defineClass1(Native Method)
  at java.lang.ClassLoader.defineClass(ClassLoader.java:760)
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  at java.lang.reflect.Method.invoke(Method.java:497)
  at net.bytebuddy.dynamic.loading.ClassInjector$UsingReflection$Dispatcher$Resolved.loadClass(ClassInjector.java:388)
  ... 5 more

I saw this related question where I do however get a collision exception (as if the constructor was defined twice).


回答1:


You cannot create a handler for a super method invocation for a constructor. The JVM's verifier ensures that any constructor calls another constructor once and only once. This call must be hard-coded into the method that invokes the constructor.

Note that this restriction holds for any Java byte code and even for scenarios where one is dealing with MethodHandles. Constructors are the big exception.

To make your exampel work, you need to invoke the super constructor either before or after the delegation. Note that you cannot access any properties that are defined by this from the interceptor (e.g. by @This or by @SuperCall, it is however possible to read the arguments) if you intercept before calling another constructor.

For your code example, simply chain the interceptor with a SuperCall such that the invocation becomes hard-coded as shown in the following example code:

new ByteBuddy().subclass(Object.class)
               .name("t.Foo")
               .constructor(any()).intercept(to(new Object() {
                 public void construct() throws Exception {
                   System.out.println("CALLING XTOR");
                 }
               }).andThen(SuperMethodCall.INSTANCE)) // This makes the difference!
               .make()
               .load(Bar.class.getClassLoader(), INJECTION)
               .getLoaded()

I agree that Byte Buddy should be more informative about this problem. I will add proper runtime handling for this scenario (i.e. the method is no longer considered for binding).



来源:https://stackoverflow.com/questions/34907382/intercepting-default-constructor-with-byte-buddy

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!