使用 Byte Buddy 在运行时添加方法注释
Add method annotation at runtime with Byte Buddy
几天来我一直在寻找 "how to add an annotation to the method at runtime" 的答案,发现了一个名为 Byte Buddy 的很棒的工具,使用了它,但仍然无法按我的需要使其工作。我确定它一定能够从这个问题中做到这一点 Can Byte Buddy create fields and method annotations at runtime?
有这个class:
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");
}
}
和此代码:
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());
}
}
向class添加注释很容易。
但是对于方法,不改变方法实现好像不行。
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());
我确定我做的不对,但不幸的是,当方法没有代码更改并且只有注释更改时找不到示例。
你在字节好友中发现了一个盲点,我想了一段时间来修复。 Byte Buddy 的早期版本不允许定义注释,但当它允许时,API 已经被广泛使用,我无法更改它,并且在实现中也需要一些位。
如果您愿意支付添加合成方法的最低价格,您可以改用 class:
new ByteBuddy().rebase(ClassThatNeedsToBeAnnotated.class)
这样做,您可以只使用当前的 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();
注解实例可以通过以下方式获取:
AnnotationDescription.Latent.Builder.ofType(AnnotationClass.class).build()
几天来我一直在寻找 "how to add an annotation to the method at runtime" 的答案,发现了一个名为 Byte Buddy 的很棒的工具,使用了它,但仍然无法按我的需要使其工作。我确定它一定能够从这个问题中做到这一点 Can Byte Buddy create fields and method annotations at runtime?
有这个class:
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");
}
}
和此代码:
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());
}
}
向class添加注释很容易。 但是对于方法,不改变方法实现好像不行。
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());
我确定我做的不对,但不幸的是,当方法没有代码更改并且只有注释更改时找不到示例。
你在字节好友中发现了一个盲点,我想了一段时间来修复。 Byte Buddy 的早期版本不允许定义注释,但当它允许时,API 已经被广泛使用,我无法更改它,并且在实现中也需要一些位。
如果您愿意支付添加合成方法的最低价格,您可以改用 class:
new ByteBuddy().rebase(ClassThatNeedsToBeAnnotated.class)
这样做,您可以只使用当前的 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();
注解实例可以通过以下方式获取:
AnnotationDescription.Latent.Builder.ofType(AnnotationClass.class).build()