bytebuddy - 添加class级注解
bytebuddy - add class level annotation
我正在尝试使用 byte-buddy 创建 java 代理,以允许在 运行 时间修改一些 classes -
FirstSeleniumTest
class 已经存在 - 我想添加如下注释:
@org.testng.annotations.Listeners(value = org.deployd.test.TestNgListener.class)
public class FirstSeleniumTest {...
这是我在代理中的 premain 方法:
new AgentBuilder.Default()
.disableClassFormatChanges()
.with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
.with(AgentBuilder.TypeStrategy.Default.REDEFINE)
.type(ElementMatchers.nameContains("org.deployd"))
.transform((builder, typeDescription, agr3, arg4) -> builder
.annotateType(AnnotationDescription.Builder.ofType(Listeners.class)
.define("value", TestNgListener.class)
.build()))
.with(AgentBuilder.Listener.StreamWriting.toSystemOut())
.installOn(instrumentation);
我在执行过程中遇到以下错误:
[Byte Buddy] DISCOVERY org.deployd.test.FirstSeleniumTest
[sun.misc.Launcher$AppClassLoader@18b4aac2, null, loaded=false]
[Byte Buddy] ERROR org.deployd.test.FirstSeleniumTest
[sun.misc.Launcher$AppClassLoader@18b4aac2, null, loaded=false]
java.lang.IllegalArgumentException: class org.deployd.agent.TestNgListener cannot be
assigned to value
at net.bytebuddy.description.annotation.AnnotationDescription$Builder.define(AnnotationDescription.java:860)
at net.bytebuddy.description.annotation.AnnotationDescription$Builder.define(AnnotationDescription.java:947)
at net.bytebuddy.description.annotation.AnnotationDescription$Builder.define(AnnotationDescription.java:935)
at org.deployd.agent.TestAgent.lambda$premain[=13=](TestAgent.java:41)
如果我手动添加注解:
@org.testng.annotations.Listeners(value = org.deployd.test.TestNgListener.class)
public class FirstSeleniumTest {...
然后没有错误 - 这意味着值 'value' 对于给定的注释是正确的。
关于我可能遗漏的任何指示,试图为已经存在的 class 创建 class 级别的注释。谢谢。
在进一步分析中,我发现注释 value
除了类型的数组与单个值。我能够通过 javassist 解决这个问题,如下所示:
AnnotationsAttribute annotationsAttribute = new AnnotationsAttribute(constPool, AnnotationsAttribute.visibleTag);
Annotation annotation = new Annotation(Listeners.class.getName(), constPool);
MemberValue[] memberValues = new MemberValue[]{new ClassMemberValue(TestNgListener.class.getName(), constPool)};
ArrayMemberValue arrayMemberValue = new ArrayMemberValue(constPool);
arrayMemberValue.setValue(memberValues);
annotation.addMemberValue("value", arrayMemberValue);
annotationsAttribute.addAnnotation(annotation);
ctClass.getClassFile().addAttribute(annotationsAttribute);
如果你想定义一个数组属性,你必须这样声明它:
AnnotationDescription.Builder.ofType(Listeners.class)
.define("value", new Class<?>[] { TestNgListener.class })
.build();
会起作用。 Byte Buddy 不像 Java 编程语言那样将此类数组视为可变参数。
我正在尝试使用 byte-buddy 创建 java 代理,以允许在 运行 时间修改一些 classes -
FirstSeleniumTest
class 已经存在 - 我想添加如下注释:
@org.testng.annotations.Listeners(value = org.deployd.test.TestNgListener.class)
public class FirstSeleniumTest {...
这是我在代理中的 premain 方法:
new AgentBuilder.Default()
.disableClassFormatChanges()
.with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
.with(AgentBuilder.TypeStrategy.Default.REDEFINE)
.type(ElementMatchers.nameContains("org.deployd"))
.transform((builder, typeDescription, agr3, arg4) -> builder
.annotateType(AnnotationDescription.Builder.ofType(Listeners.class)
.define("value", TestNgListener.class)
.build()))
.with(AgentBuilder.Listener.StreamWriting.toSystemOut())
.installOn(instrumentation);
我在执行过程中遇到以下错误:
[Byte Buddy] DISCOVERY org.deployd.test.FirstSeleniumTest
[sun.misc.Launcher$AppClassLoader@18b4aac2, null, loaded=false]
[Byte Buddy] ERROR org.deployd.test.FirstSeleniumTest
[sun.misc.Launcher$AppClassLoader@18b4aac2, null, loaded=false]
java.lang.IllegalArgumentException: class org.deployd.agent.TestNgListener cannot be
assigned to value
at net.bytebuddy.description.annotation.AnnotationDescription$Builder.define(AnnotationDescription.java:860)
at net.bytebuddy.description.annotation.AnnotationDescription$Builder.define(AnnotationDescription.java:947)
at net.bytebuddy.description.annotation.AnnotationDescription$Builder.define(AnnotationDescription.java:935)
at org.deployd.agent.TestAgent.lambda$premain[=13=](TestAgent.java:41)
如果我手动添加注解:
@org.testng.annotations.Listeners(value = org.deployd.test.TestNgListener.class)
public class FirstSeleniumTest {...
然后没有错误 - 这意味着值 'value' 对于给定的注释是正确的。
关于我可能遗漏的任何指示,试图为已经存在的 class 创建 class 级别的注释。谢谢。
在进一步分析中,我发现注释 value
除了类型的数组与单个值。我能够通过 javassist 解决这个问题,如下所示:
AnnotationsAttribute annotationsAttribute = new AnnotationsAttribute(constPool, AnnotationsAttribute.visibleTag);
Annotation annotation = new Annotation(Listeners.class.getName(), constPool);
MemberValue[] memberValues = new MemberValue[]{new ClassMemberValue(TestNgListener.class.getName(), constPool)};
ArrayMemberValue arrayMemberValue = new ArrayMemberValue(constPool);
arrayMemberValue.setValue(memberValues);
annotation.addMemberValue("value", arrayMemberValue);
annotationsAttribute.addAnnotation(annotation);
ctClass.getClassFile().addAttribute(annotationsAttribute);
如果你想定义一个数组属性,你必须这样声明它:
AnnotationDescription.Builder.ofType(Listeners.class)
.define("value", new Class<?>[] { TestNgListener.class })
.build();
会起作用。 Byte Buddy 不像 Java 编程语言那样将此类数组视为可变参数。