ByteBuddy-在Java代理中读取类注释

时间:2019-08-25 17:13:09

标签: java byte-buddy javaagents

在尝试使用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对象,将会更容易。

1 个答案:

答案 0 :(得分:1)

Byte Buddy已经通过TypeDescription API公开了有关类注释的所有信息,您不应加载类,因为在转换期间加载的类会在应用转换之前加载该类,并中止使用您观察到的错误。而是实现自己的匹配器:

.type(type -> check(type.getDeclaredAnnotations().ofType(SomeAnnotation.class).load())

Byte Buddy将为您表示注释,而无需加载载体类本身,而是使用其自己的类文件处理器来表示它。

在安装代理构建器之前,应确保已加载注释类,以避免此确切注释的圆形性。