简体   繁体   中英

ByteBuddy - Read class annotations in a java agent

I am trying to access annotations of a class before applying some transformation in a java agent implemented with ByteBuddy. To access the annotations, I am trying to load the Class object, but it seems that this creates a duplicate class definition.

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);
    }
}

A simple class that just creates an instance of the class TestClass that is annotated with the expected annotation, throws the following exception:

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();
    }
}

I am trying to implement the agent like in the example described in: Easily-Create-Java-Agents-with-ByteBuddy

Is there a way to load the Class object without causing this issue or a way to access the annotations using the arguments passed to the transformation() method?

The transformation should be able to implement new interfaces and not only override methods this is why I think I cannot use "ForAdvice".

UPDATE The following loop finds the TestClass only after the Class.forName() is executed. This means that the class has not been loaded and so probably there is no hope to use Class.forName to get the annotations.

for (Class<?> t : inst.getAllLoadedClasses()) {
    System.out.println("Class name: " + t.getName());
}

It is possible to get the annotations and the full information about a class using the net.bytebuddy.description.type.TypeDescription instance passed to the transform() method.

The problem is that, for example, I need the Method objects that can be called using reflection. It would be easier if I could somehow access the Class object for the class that is being transformed.

Byte Buddy exposes all information on annotations of a class via the TypeDescription API already, you should not load classes as a class that is loaded during a transformation loads this class before the transformation is applied and aborts class loading with the error you observe. Instead, implement your own matcher:

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

Byte Buddy will represent the annotation for you without loading the carrier class itself but rather represent it using its own class file processor.

You should make sure the annotation class is loaded before installing your agent builder to avoid a circularity for this exact annotation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM