ByteBuddy - 在 java 代理中阅读 class 注释
ByteBuddy - Read class annotations in a java agent
我试图在使用 ByteBuddy 实现的 java 代理中应用一些转换之前访问 class 的注释。
为了访问注释,我试图加载 Class 对象,但似乎这会创建一个重复的 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);
}
}
一个简单的 class 只是创建了一个 class 测试 Class 的实例,它用预期的注释进行了注释,抛出以下异常:
Exception in thread "main" java.lang.LinkageError: loader (instance of
sun/misc/Launcher$AppClassLoader): attempted duplicate class
definition for name: "TestClass"
public class AgentTest {
public static void main (String[] args) {
TestClass pet = new TestClass();
}
}
我正在尝试像以下所述的示例中那样实施代理:Easily-Create-Java-Agents-with-ByteBuddy
有没有一种方法可以加载 Class 对象而不会导致这个问题,或者有一种方法可以使用传递给 transformation() 方法的参数来访问注释?
转换应该能够实现新接口,而不仅仅是覆盖方法,这就是为什么我认为我不能使用 "ForAdvice"。
更新
以下循环仅在 Class.forName() 执行后才找到 TestClass。这意味着 class 尚未加载,因此可能没有希望使用 Class.forName 来获取注释。
for (Class<?> t : inst.getAllLoadedClasses()) {
System.out.println("Class name: " + t.getName());
}
可以使用传递给 transform() 方法的 net.bytebuddy.description.type.TypeDescription 实例获取有关 class 的注释和完整信息。
问题是,例如,我需要可以使用反射调用的方法对象。如果我能以某种方式访问正在转换的 class 的 Class 对象,那就更容易了。
Byte Buddy 已经通过 TypeDescription
API 公开了有关 class 注释的所有信息,您不应将 classes 作为 class 加载在转换期间加载的在应用转换之前加载此 class 并中止 class 加载并出现您观察到的错误。相反,实现你自己的匹配器:
.type(type -> check(type.getDeclaredAnnotations().ofType(SomeAnnotation.class).load())
Byte Buddy 将在不加载载体 class 本身的情况下为您呈现注释,而是使用其自己的 class 文件处理器来呈现注释。
您应该确保在安装您的代理生成器之前加载注释 class 以避免此确切注释的循环。
我试图在使用 ByteBuddy 实现的 java 代理中应用一些转换之前访问 class 的注释。 为了访问注释,我试图加载 Class 对象,但似乎这会创建一个重复的 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);
}
}
一个简单的 class 只是创建了一个 class 测试 Class 的实例,它用预期的注释进行了注释,抛出以下异常:
Exception in thread "main" java.lang.LinkageError: loader (instance of sun/misc/Launcher$AppClassLoader): attempted duplicate class definition for name: "TestClass"
public class AgentTest {
public static void main (String[] args) {
TestClass pet = new TestClass();
}
}
我正在尝试像以下所述的示例中那样实施代理:Easily-Create-Java-Agents-with-ByteBuddy
有没有一种方法可以加载 Class 对象而不会导致这个问题,或者有一种方法可以使用传递给 transformation() 方法的参数来访问注释?
转换应该能够实现新接口,而不仅仅是覆盖方法,这就是为什么我认为我不能使用 "ForAdvice"。
更新 以下循环仅在 Class.forName() 执行后才找到 TestClass。这意味着 class 尚未加载,因此可能没有希望使用 Class.forName 来获取注释。
for (Class<?> t : inst.getAllLoadedClasses()) {
System.out.println("Class name: " + t.getName());
}
可以使用传递给 transform() 方法的 net.bytebuddy.description.type.TypeDescription 实例获取有关 class 的注释和完整信息。
问题是,例如,我需要可以使用反射调用的方法对象。如果我能以某种方式访问正在转换的 class 的 Class 对象,那就更容易了。
Byte Buddy 已经通过 TypeDescription
API 公开了有关 class 注释的所有信息,您不应将 classes 作为 class 加载在转换期间加载的在应用转换之前加载此 class 并中止 class 加载并出现您观察到的错误。相反,实现你自己的匹配器:
.type(type -> check(type.getDeclaredAnnotations().ofType(SomeAnnotation.class).load())
Byte Buddy 将在不加载载体 class 本身的情况下为您呈现注释,而是使用其自己的 class 文件处理器来呈现注释。
您应该确保在安装您的代理生成器之前加载注释 class 以避免此确切注释的循环。