简体   繁体   English

如何在现有类中定义新方法并使用 bytebuddy 在同一类中的现有方法中添加对它的调用?

[英]How to define a new method inside an existing class and add a call to it in an existing method inside the same class using bytebuddy?

I have a class which looks like below我有一个看起来像下面的类

public class HelloWorld{
  public void sayHelloWorld(){
    System.out.println("Hello World");
  }
}

Now I would like to add another method to the HelloWorld class using bytebuddy and add a call to the new method in sayHelloWorld .现在我想使用 bytebuddy 向HelloWorld类添加另一个方法,并在sayHelloWorld 中添加对新方法的调用。 So hypothetically the class would look like this after bytebuddy does it's magic.因此,假设在 bytebuddy 发挥魔力之后,该类将看起来像这样。 (I know that bytebuddy works with bytecode and not java source files. The below code is just for illustration purpose.) (我知道 bytebuddy 使用字节码而不是 java 源文件。以下代码仅用于说明目的。)

public class HelloWorld{
  public void sayHelloWorld(){
    System.out.println("Hello World");
    sayHelloAgain()
  }
  public void sayHelloAgain(){
    System.out.println("Hello Again")
  }
}
  1. Firstly, is this possible with bytebuddy?首先,这对bytebuddy有可能吗?
  2. Secondly, if it is possible, how can I do it?其次,如果可能,我该怎么做? I have understood that bytebuddy can be used to redefine methods, but not modify the method body.我已经了解 bytebuddy 可用于重新定义方法,但不能修改方法体。 Is this true?这是真的?

It would be great if someone could shed some light on this.如果有人能对此有所了解,那就太好了。 TIA!蒂亚!

Byte Buddy allows you to do this in various ways. Byte Buddy 允许您以各种方式执行此操作。 The most straight forward way would be to define an interceptor that implements sayHelloAgain to which Byte Buddy creates a delegation:最直接的方法是定义一个实现sayHelloAgain的拦截器,Byte Buddy 创建一个委托:

public class HelloAgainDelegate {
  public static void sayHelloAgain() {
    System.out.println("Hello again");
  }
}

You can then define the method on the redefined class and rebase the sayHelloWorld method to first invoke the original method and then invoke the other method:然后,您可以在重新定义的类上定义该方法,并重新定义sayHelloWorld方法以首先调用原始方法,然后调用另一个方法:

Class<?> type = new ByteBuddy()
  .rebase(HelloWorld.class)
  .defineMethod("sayHelloAgain", void.class, Visibility.PUBLIC)
  .intercept(MethodDelegation.to(HelloAgainDelegate.class))
  .method(named("sayHelloWorld"))
  .intercept(SuperMethodCall.INSTANCE
    .andThen(MethodCall.invoke(named("sayHelloAgain"))))
  .make()
  .load(HelloWorld.class.getClassLoader(), 
        ClassLoadingStrategy.Default.CHILD_FIRST)
  .getLoaded();

Object instance = type.newInstance();
type.getMethod("sayHelloWorld").invoke(instance);
type.getMethod("sayHelloAgain").invoke(instance);

In Java code, the rebased class would look something like this:在 Java 代码中,重新定位的类看起来像这样:

public class HelloWorld {
  synthetic void sayHelloWorld$origin() {
    System.out.println("Hello World");
  }  

  public void sayHelloWorld() {
    sayHelloWorld$origin();
    sayHelloAgain();
  }

  public void sayHelloAgain() {
    HelloAgainInterceptor.sayHelloAgain();
  }
}

If this delegation is not an option for you, you can also use Advice to inline the code from a template class:如果此委托不适合您,您还可以使用Advice来内联模板类中的代码:

class HelloAgainAdvice {
  @Advice.OnMethodExit
  static void sayHelloAgain() {
    System.out.println("Hello again");
  }
}

Instead of the MethodDelegation , you would use this class via Advice.to(HelloAgainAdvice.class) .您可以通过Advice.to(HelloAgainAdvice.class)使用此类,而不是MethodDelegation As the code is copied, you will not be able to set break points but your redefined class will be self-contained.复制代码后,您将无法设置断点,但您重新定义的类将是独立的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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