在尝试使用ByteBuddy实现的Java代理中进行某些转换之前,我尝试访问类的注释。 为了访问批注,我正在尝试加载Class对象,但这似乎会创建重复的类定义。
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.matcher.ElementMatchers;
import java.lang.instrument.Instrumentation;
public class SimpleTestAgent {
public static void premain(String arg, Instrumentation inst) {
new AgentBuilder.Default()
.type(ElementMatchers.isAnnotatedWith(SomeAnnotationType.class))
.transform((builder, type, classLoader, javaModule) -> {
try {
Class loadedClass = Class.forName(type.getName(), true, classLoader);
} catch (ClassNotFoundException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
return builder;
})
.installOn(inst);
}
}
一个简单的类仅创建类TestClass的实例,该实例使用预期的注释进行注释,并引发以下异常:
线程“ main”中的异常java.lang.LinkageError:加载程序(实例为 sun / misc / Launcher $ AppClassLoader):尝试复制类 名称的定义:“ TestClass”
public class AgentTest {
public static void main (String[] args) {
TestClass pet = new TestClass();
}
}
我正在尝试像Easily-Create-Java-Agents-with-ByteBuddy
中描述的示例那样实现代理。有没有一种方法可以加载Class对象而不会导致此问题,或者有一种方法可以使用传递给transform()方法的参数来访问批注?
该转换应该能够实现新的接口,而不仅仅是重写方法,这就是为什么我不能使用“ ForAdvice”的原因。
更新 以下循环仅在执行Class.forName()之后找到TestClass。这意味着该类尚未加载,因此可能没有希望使用Class.forName获取注释。
for (Class<?> t : inst.getAllLoadedClasses()) {
System.out.println("Class name: " + t.getName());
}
可以使用传递给transform()方法的net.bytebuddy.description.type.TypeDescription实例获取有关类的注释和完整信息。
问题是,例如,我需要可以使用反射调用的Method对象。如果我能以某种方式访问要转换的类的Class对象,将会更容易。
答案 0 :(得分:1)
Byte Buddy已经通过TypeDescription
API公开了有关类注释的所有信息,您不应加载类,因为在转换期间加载的类会在应用转换之前加载该类,并中止使用您观察到的错误。而是实现自己的匹配器:
.type(type -> check(type.getDeclaredAnnotations().ofType(SomeAnnotation.class).load())
Byte Buddy将为您表示注释,而无需加载载体类本身,而是使用其自己的类文件处理器来表示它。
在安装代理构建器之前,应确保已加载注释类,以避免此确切注释的圆形性。