Quarkus BuildStep

132 views Asked by At

I am trying to transform annotation data using BuildStep as stated on the link below

https://quarkus.io/guides/cdi-integration#annotations_transformer_build_item

However, I am not seeing any indication this is working. I can't verify during build time what is wrong and there is no change at runtime. Below is the sample code:

    public class TestTelemetryBuilder {
    
        @BuildStep
        AnnotationsTransformerBuildItem transform() {
            return new AnnotationsTransformerBuildItem(new AnnotationsTransformer() {
    
                @Override
                public boolean appliesTo(final org.jboss.jandex.AnnotationTarget.Kind kind) {
                    return kind == org.jboss.jandex.AnnotationTarget.Kind.CLASS;
                }
    
                @Override
                public void transform(final TransformationContext context) {
                    if ("io.quarkus.redis.datasource.value.ValueCommands"
                            .equals(context.getTarget().asClass().name().toString())) {
                        List<MethodInfo> methods = context.getTarget().asClass().methods();
                        AnnotationInstance annot = AnnotationInstance.builder(DotName.createSimple(
                                "io.opentelemetry.instrumentation.annotations.WithSpan")).build();
                        methods.forEach(t -> t.annotations()
                                .add(annot));
                    }
                }
            });
        }
    }

I want to add the WithSpan annotation to all the methods on the Redis ValueCommands class whenever called. Does this work only when the class is injected? I tried with RedisDataSource which is injected but couldn't get it to work. Is there anything else I need to setup/configure?

1

There are 1 answers

1
Ladicek On

So the AnnotationsTransformerBuildItem is used to modify the internal model of classes that the given Quarkus component uses. It doesn't modify bytecode or anything like that, so you can't observe the changes directly, only indirectly (through changed behavior).

There are 2 classes named AnnotationsTransformerBuildItem:

  • io.quarkus.arc.deployment.AnnotationsTransformerBuildItem for ArC, the CDI container in Quarkus
  • io.quarkus.resteasy.reactive.server.spi.AnnotationsTransformerBuildItem for RESTEasy Reactive, the JAX-RS implementation in Quarkus

Since @WithSpan is treated as an interceptor binding in Quarkus, you need the ArC's AnnotationsTransformerBuildItem.

Assuming you have the ArC's AnnotationsTransformerBuildItem, there are 3 problems:

  1. You're using the transformation API incorrectly. Adding an annotation to the set of annotations returned from MethodInfo is not supposed to work and it's not going to work. The transformation API is basically a callback. You're called with a TransformationContext for any given element, and you have to modify the annotations through the TransformationContext. Since you're trying to modify annotations on the methods of io.quarkus.redis.datasource.value.ValueCommands, your appliesTo method should be return kind == AnnotationTarget.Kind.METHOD and the transform method should check if the method it is given is declared on the class you need.

  2. But even if you used the transformation API correctly, it still wouldn't work. You're trying to modify annotations on io.quarkus.redis.datasource.value.ValueCommands, which is an interface. An interface is never a bean class, and CDI never inherits annotations from interfaces, so such transformation is useless.

  3. Even if you found the concrete implementation of ValueCommands, it still wouldn't work. Adding an interceptor binding to a class only makes sense if that class is a CDI managed bean (also known as class-based bean). Most of the API exposed by the Redis client are not CDI beans at all, and those that are (such as RedisDataSource that you can inject) are not managed beans (they are synthetic beans actually). So none of that can actually be intercepted.

To sum up, making sure that the Redis calls are properly traced is not possible using annotation transformations.

The good news is, the underlying Vert.x Redis client implementation has gained native support for tracing in version 4.4.5. This version is used in Quarkus since version 3.4 (which was released a few days ago), so it should either work out of the box once you upgrade, or it should be fairly simple to implement on the Quarkus side. If Redis command tracing doesn't work with Quarkus 3.4, please file a feature request.