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

使用ByteBuddy进行链/转换方法调用

水铭晨
2023-03-14

使用ByteBuddy,我可以通过调用另一个实例方法并转换结果来实现一个实例方法吗?

例如(玩具):

public abstract class Foo {
  public String bar() {
    return "bar";
  }

  public abstract int baz();
}

鉴于上述情况,我能否实现baz,以便它调用bar()返回返回字符串的长度?也就是说,好像它是:

public int baz() {
  return bar().length();
}

我天真地尝试了以下方法:

Method bar = Foo.class.getDeclaredMethod("bar");
Method baz = Foo.class.getDeclaredMethod("baz");

Method length = String.class.getDeclaredMethod("length");

Foo foo = new ByteBuddy()
  .subclass(Foo.class)
  .method(ElementMatchers.is(baz))
  .intercept(
    MethodCall.invoke(bar)                 // call bar()...
      .andThen(MethodCall.invoke(length))  // ... .length()?
  ).make()
  .load(Foo.class.getClassLoader())
  .getLoaded()
  .newInstance();

System.out.println(foo.baz());

然而,看起来我的想法是错误的,,然后在第一次调用的返回值上调用();它看起来像是在生成的实例上调用的。

Exception in thread "main" java.lang.IllegalStateException: 
  Cannot invoke public int java.lang.String.length() on class Foo$ByteBuddy$sVgjXXp9
    at net.bytebuddy.implementation.MethodCall$MethodInvoker$ForContextualInvocation
    .invoke(MethodCall.java:1667)

我还试过一个拦截器:

class BazInterceptor {
  public static int barLength(@This Foo foo) {
    String bar = foo.bar();
    return bar.length();
  }
}

与:

Foo foo = new ByteBuddy()
  .subclass(Foo.class)
  .method(ElementMatchers.is(baz))
  .intercept(MethodDelegation.to(new BazInterceptor()))
  // ...etc.

这运行了,但产生了毫无意义的结果870698190,在barLength()中设置断点和/或添加打印语句表明它永远不会被调用;所以很明显,我也没有正确地理解拦截器或@这个

如何让ByteBuddy调用一个方法,然后在其返回值上调用另一个方法?

根据k5的回答:BazInterceptor在以下情况下工作:

  • 我们委托给new BazInterceptor(),如上所述,但使barLlong()成为实例方法,或:
  • 我们将barLlong()保留为类方法,但委托给BazInterceptor.class而不是实例。

我怀疑870698190正在委托给bazzinterceptor实例的hashCode(),尽管我实际上没有检查。

共有2个答案

连德水
2023-03-14

您使用实例作为拦截器,这意味着首选实例方法(可能根本不接受静态方法)。有一个实例方法与int baz()方法的签名匹配,它是int hashCode()。您得到的数字是新的BazInterceptor()实例的哈希代码。

我知道的选项:

  • bar中删除静态,这样它实际上将用于拦截。
  • 将类添加为拦截器. intercept(Method odDelegation.to(BazInterceptor.class))

我更喜欢第二个选项,因为您不使用BazInterceptor实例的任何字段/状态。

崔恺
2023-03-14

Byte Buddy目前没有好的方法,但这将是一个易于添加的功能。您可以在GitHub上跟踪进度。一旦我有时间,我会添加它。

如果现在想实现这样的链式调用,可以在Java代码中实现它们,并使用Advice组件内联这些代码。或者,您可以通过基于MethodInvocation实例创建自己的ByteCodeAppender来更明确地编写字节码,但您必须手动加载参数。

 类似资料:
  • 本文向大家介绍C#调用VB进行简繁转换的方法,包括了C#调用VB进行简繁转换的方法的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了C#调用VB进行简繁转换的方法。分享给大家供大家参考。具体分析如下: 首先在C#项目中引用Microsoft.VisualBasic.dll,版本自己选择合适的 然后在项目中添加引用:using Microsoft.VisualBasic; 转换: 转为繁体:

  • 我的项目工作正常,直到我添加了Facebook依赖。我已经开始得到这个错误。我看过很多问题,这个问题似乎与MultiDex有关。但没有一个办法对我有用 即使在我删除了我添加的内容之后,它仍然会显示出来,而且gradle在构建时似乎比平时花费了很多时间 这是我的身材。格拉德尔

  • 我正在使用ByteBuddy实现字节码转换,操作过程是一个多步骤的过程。因此,操作必须能够: 扩充原有方法 对于1。我使用了一个通过以下方式应用的OnMethodExit建议: 使用方法的增强代码(有效地设置字段的值)。创建新方法时,我按如下方式构建它们: 通过以为参数的静态方法使用运行时实例。 简而言之:如果前面的转换遵循后者,我看不到前面的转换应用。实际执行顺序如下: 我的类型得到处理,并通过

  • 我想将XMl转换为另一种XMl格式。假设我在ats中有一个逻辑。埃姆沃。使改变TransformXml java文件如何集成以在camel上下文输入中转换tis(file:///d:/in)是xml文件,我想将其另存为xml。我已经将此文件作为bean类添加到camel

  • 我现在正在使用最新的Android架构组件,尤其是ViewModel和LiveData。 我遇到的情况是,这里建议的SingleLiveEvent是相关的,即我返回一个错误,我只想显示一次警报。在向活动发送值之前,我需要将错误映射到视图中更合适的对象。我使用了一个转换来实现这一点。 最后,我有一个ViewModel,看起来像: 在我的存储库中,我使用的是SingleLive事件: 这很有效,但我注

  • 我正在尝试使用JOLT(使用NiFi JoltTransformJson处理器)将JSON转换为不同的格式。对于单个JSON记录,正在使用的JOLT在JOLT应用程序演示中运行良好,而如果我使用多个JSON记录执行,那么我在JOLT应用程序演示中没有得到预期的输出。有人能告诉我在JOLT规范中需要做哪些额外的更改来处理多个JSON记录吗? 示例输入json JOLT使用: 预期输出JSON: