当前位置: 首页 > 知识库问答 >
问题:

使用字节伙伴拦截默认构造函数

益富
2023-03-14

我正在尝试用Byte Buddy拦截构造函数调用,这是我的示例代码:

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 ();
  }
}
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

我看到了这个相关的问题,但是,我得到了一个冲突异常(就好像构造函数被定义了两次)。

共有1个答案

厍晋鹏
2023-03-14

不能为构造函数的超级方法调用创建处理程序。JVM的验证器确保任何构造函数调用另一个构造函数一次且仅一次。此调用必须硬编码到调用构造函数的方法中。

注意,这个限制适用于任何Java字节代码,甚至适用于处理methodhandle的场景。构造函数是一个很大的例外。

要使exampel工作,您需要在委派之前或之后调用超级构造函数。请注意,如果在调用另一个构造函数之前进行拦截,则无法从拦截器访问由this定义的任何属性(例如,由@this或由@supercall定义,但可以读取参数)。

对于您的代码示例,只需使用supercall链接拦截器,使调用变成硬编码,如下面的示例代码所示:

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()

我同意Byte Buddy应该提供更多关于这个问题的信息。我将为这个场景添加适当的运行时处理(即不再考虑绑定该方法)。

 类似资料:
  • 如何在构造函数拦截器中启动对象字段? 我在Buddy代码中创建了一个字节构造函数。 构造函数首先将参数保存到私有字段。然后它创建集合。然后它调用以下拦截器来填充该集合。 最好在拦截器中实例化variableNamedField字段,因为事实证明,每次创建新的类实例时,variableNamedField字段都是用相同的HashMap对象实例化的。但是,我只能通过@FieldValue注释将现有字段

  • 我必须将注释XmlElementWrapper和XmlElement添加到列表类型的字段,但是这些注释需要名称。我想把属性名设置为字段名。我愿意: 这是我的拦截器: 这是目标类的一部分: 但我有一个例外: [public static void factory.framework.SetterListInterceptor.getter(java.lang.reflect.Method)、publ

  • 我试图通过java应用程序中的所有外部调用传递监视/跟踪信息。为了使其透明,我尝试使用byte-buddy,但在使其工作时遇到了一些困难。 为了跟踪每个传入的(http)请求,我截获了HttpServlet。service(),从HttpServletRequest中提取令牌头,并将其放在名为TokenHolder的类中的静态ThreadLocal中。 为了跟踪每个传出(超文本传输协议)请求,我拦

  • 我在使用Byte Buddy时遇到了一个简单的问题,下面是我的代码: 我希望工作并将调用转发到受人尊敬的拦截器实例,但是我得到这个异常: 最奇怪的部分在异常消息的最后: 我做错了什么?

  • 问题内容: 默认构造函数到底是什么?你能告诉我以下哪个是默认构造函数,它与其他构造函数有何不同? 问题答案: 他们都不是。如果定义,则不是默认值。 除非你定义另一个构造函数,否则默认构造函数是自动生成的无参数构造函数。任何未初始化的字段都将设置为其默认值。对于你的榜样,它看起来像这样假设的类型String,int以及int,那类本身是公共的: 这与 完全没有构造函数。但是,如果定义至少一个构造函数

  • 问题内容: 所有, 我正在尝试在一些古老的Java代码中进行一些单元测试(无接口,无抽象等)。 这是一个使用ServletContext的servlet(我假设它是由Tomcat设置的),并且它的数据库信息在web.xml / context.xml文件中设置。现在,我已经弄清楚了如何制作Fake ServletContext,但是代码已经 遍布整个地方(因此替换它是不可行的)。我需要找到一种方法