使用 Byte Buddy 在运行时添加方法注释

lub*_*b0v 5 java annotations byte-buddy

几天来,我一直在寻找“如何在运行时向方法添加注释”的答案,并找到了这个名为 Byte Buddy 的很棒的工具,使用了它,但仍然无法按我的需要工作。我确定它必须能够从这个问题Can Byte Buddy create fields and method annotations at runtime?

有这个类:

public class ClassThatNeedsToBeAnnotated {
  public void method(int arg1, String arg2) {
    // code that we don't want to touch at all, leave it as is
    System.out.println("Called method with arguments " + arg1 + " " + arg2);
  }

  public void method() {
    System.out.println("Called method without arguments");
  }
}
Run Code Online (Sandbox Code Playgroud)

和这个代码:

 public class MainClass {
      public static void main(String[] args) {
        ByteBuddyAgent.install();

        AnnotationDescription description = AnnotationDescription.Builder.ofType(MyClassAnnotation.class)
            .define("value", "new")
            .build();

        new ByteBuddy()
            .redefine(ClassThatNeedsToBeAnnotated.class)
            .annotateType(description)
            .make()
            .load(ClassThatNeedsToBeAnnotated.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent());

      }
}
Run Code Online (Sandbox Code Playgroud)

添加注释很容易。但是对于方法来说,不改变方法实现似乎是不可能的。

Method existingMethod = ClassThatNeedsToBeAnnotated.class.getDeclaredMethods()[0];
AnnotationDescription annotationDescription = AnnotationDescription.Builder.ofType(MyMethodAnnotation.class)
    .build();
new ByteBuddy()
    .redefine(ClassThatNeedsToBeAnnotated.class)
    .annotateType(description)
    .method(ElementMatchers.anyOf(existingMethod))
    // here I don't want to intercept method, I want to leave the method code untouched. How to do that?
    .annotateMethod(annotationDescription)
    .make()
    .load(ClassThatNeedsToBeAnnotated.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent());
Run Code Online (Sandbox Code Playgroud)

我确定我只是没有做对,但不幸的是,当方法没有代码更改而只有注释更改时,我找不到示例。

Raf*_*ter 3

你在 Byte Buddy 中发现了一个盲点,我一度想修复它。Byte Buddy 的早期版本不允许定义注释,但当它允许时,API 已经被广泛使用,我无法更改它,并且在实现中也需要一些位。

如果您愿意付出最低的代价来添加合成方法,则可以重新设置该类的基数:

new ByteBuddy().rebase(ClassThatNeedsToBeAnnotated.class)
Run Code Online (Sandbox Code Playgroud)

这样做,您只需使用当前的 API 并添加SuperMethodCall. 这将在变基中调用完全相同的方法。

Byte Buddy 的增强功能可在此处跟踪:https ://github.com/raphw/byte-buddy/issues/627

更新:在即将推出的 Byte Buddy 1.10.0 中,可以通过以下方式实现:

new ByteBuddy()
  .redefine(ClassThatNeedsToBeAnnotated.class)
  .visit(new MemberAttributeExtension.ForMethod()
    .annotateMethod(someAnnotation)
    .on(matcher))
  .make();
Run Code Online (Sandbox Code Playgroud)

注释实例可以通过以下方式获取: AnnotationDescription.Latent.Builder.ofType(AnnotationClass.class).build()