0

I want to add an annotation to all methods of some classes in a java agent, I did this and it worked , but I'm not sure if that's the right way because i saw other examples that i didn't understand. I don't understand the intercept(SuperMethodCall.INSTANCE) ? what does it mean? I don't want the class code to change in any way, its not going to be my code , it will be customer's code.

    private static void premain(Instrumentation inst, boolean fromPremain) {

    try {

        new AgentBuilder.Default()
                .type(ElementMatchers.named("com.example.TestClass"))
                .transform(new AgentBuilder.Transformer() {
                    @Override
                    public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription, ClassLoader classLoader, JavaModule module, ProtectionDomain protectionDomain) {

                        try {
                            AnnotationDescription annotationDescription = AnnotationDescription.Latent.Builder.ofType((Class<? extends Annotation>) Class.forName("com.example.MyAnnotation", false, classLoader)).build();


                            return builder
                                    .method(ElementMatchers.isDeclaredBy(typeDescription))
                                    .intercept(SuperMethodCall.INSTANCE)
                                    .annotateMethod(annotationDescription);
                        } catch (Throwable e) {
                            LOGGER.log(Level.SEVERE, "got exception in bytebuddy transformer", e);
                            return builder;
                        }

                    }
                }).installOn(inst);


    } catch (Throwable ex) {
        LOGGER.log(Level.SEVERE, "got exception while starting agent", ex);
    }
}
2
  • As you mention customer's code: when feasible I would refrain from byte code manipulation. Somehow marker interfaces or whatever + good error reporting might be more maintainable. But I do not know anything about your use-case, Runtime annotations over byte-buddy makes me simply wonder. Commented May 8, 2024 at 20:31
  • 1
    Instead of performing an unchecked type cast like (Class<? extends Annotation>) Class.forName("com.example.MyAnnotation", false, classLoader) you should use Class.forName("com.example.MyAnnotation", false, classLoader) .asSubclass(Annotation.class) Commented May 16, 2024 at 6:56

2 Answers 2

1

A better way would be to use MemberAttributeExtension what allows you to add an annotation without touching the method. This way, Byte Buddy does not have to refine methods other than adding the attribute.

Currently, you create a new method and add the existing method in a synthetic container what is unneccessary.

Sign up to request clarification or add additional context in comments.

3 Comments

Thank you eventually I changed it to MemberAttributeExtension and it works fine.
maybe you can help in another related issue. I'm injecting opentelemetry WithSpan annotation. the otel API must be in the classpath. I can inject it on startup using inst.appendToSystemClassLoaderSearch and it works. but maybe the otel API is already in the application classpath then i don't want to inject it again. it may also be complex class load hierarchy like on web servers. Do you think that during the transformation if WithSpan can't be loaded only then inject otel API to the system class loader?
You can check using Class.forName if a known class can be found.
0

eventually i changed it to

 Configuration configuration = new Configuration();
 new AgentBuilder.Default()
                    .type(TypeMatchers.create(configuration))
                    .transform((builder, typeDescription, classLoader, module, protectionDomain) -> {

                        try {
                            @SuppressWarnings("unchecked")
                            AnnotationDescription annotationDescription =
                                    AnnotationDescription.Latent.Builder.ofType((Class<? extends Annotation>) Class.forName(WITH_SPAN_CLASS_NAME, false, classLoader)).build();


                            return builder
                                    .visit(new MemberAttributeExtension.ForMethod().annotateMethod(annotationDescription)
                                            .on(MethodMatchers.create(typeDescription, configuration)));
                        } catch (Throwable e) {
                            LOGGER.log(Level.SEVERE, "got exception in bytebuddy transformer", e);
                            return builder;
                        }

                    }).installOn(inst);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.