byte-buddy icon indicating copy to clipboard operation
byte-buddy copied to clipboard

Is it possible to bind a Logger as a constant?

Open jafarre-bi opened this issue 2 months ago • 5 comments

Hello, In the advice I'm writing, I need an instance of java.util.logging.Logger and I don't want to request it by name every time. As a first approach, I have added a static field, initialised at the end of static initialisation, and I'm passing it with @FieldValue. This implies I need to rebase the class rather than decorate it. Is it possible to bind the logger instance as a constant instead, in the same way I would, for instance, with a String? Thanks!

jafarre-bi avatar Oct 27 '25 17:10 jafarre-bi

You could attempt a dynamic constant with constandynamic. This requires that the class can access a bootstrap method and a class level of Java 11.

raphw avatar Oct 27 '25 17:10 raphw

I'm trying to do it with @Advice.DynamiConstant. Not sure if that's the recommended approach. I think I'm not getting it, because I have a couple of important doubts:

  • What exactly is the bootstrapName? The fully-qualified name of a method? The fully-qualified name of a field holding a method handle?
  • How can I pass an additional argument to the bootstrap method? Concretely, a String. I can declare the argument types, but I don't see how to pass an argument.

jafarre-bi avatar Oct 27 '25 21:10 jafarre-bi

The name is something that is mandatory and is provided to the bootstrap method. You have to set a name, but can ignore it. Often the empty string is used in such a case.

You can pass a bootstrap handler that passes arguments that need to be constant. A string will work.

You can have a look at the tests in Byte Buddy to see how this is working.

raphw avatar Oct 28 '25 14:10 raphw

Great! The test net.bytebuddy.test.precompiled.v11.AdviceDynamicConstant clarified the usage of the annotation attributes. But I still don't understand what you mean by passing a bootstrap handler that passes arguments that need to be constant. In that test, the bootstrap handler is bootstrapdynamic(MethodHandles.Lookup, String, Object...). The parameter types declared in DynamicConstant.bootstrapParameterTypes are precisely those (MethodHandles.Lookup, String, Object[]). But I can't see what values will be passed to the Object[]. In net.bytebuddy.utility.JavaConstantDynamicTest, JavaConstant.Dynamic.bootstrap is used. It explicitly takes an Object array with the constant arguments that will be passed to the actual bootstrap method. I can't see anything equivalent for the DynamicConstant annotation in the advice. To make sure we are on the same page, I show you here what I'm trying to achieve:

@OnMethodEnter()
public static void myAdvice(
        @Origin("#t") String className,
        @DynamicConstant(
                name = "<className>",
                bootstrapType = INVOKE_STATIC,
                bootstrapOwner = MyAdvice.class,
                bootstrapName = "bootstrap",
                bootstrapParameterTypes = String.class,
                bootstrapReturnType = Logger.class
        ) SomeType myConstant) {}

public static Logger bootstrap(MethodHandles.Lookup lookup, String name) {
        return Logger.getLogger(name);
}

So I need one dynamic constant that requires the class name of the instrumented method as input to the bootstrap method. One possibility is to pass it via the @DynamicConstant.name, but my only way to know the class name is by using @Origin. I think the lookup parameter is required, right? Otherwise, I could directly use Logger.getLogger as the bootstrap method. I can't see how to put things together. Thanks for your help!

jafarre-bi avatar Oct 29 '25 00:10 jafarre-bi

You need to create a custom factory of net.bytebuddy.asm.Advice.OffsetMapping.ForDynamicConstant. The additional arguments can be provided as arguments.

You return this instance from OffsetMapping.Factory.

raphw avatar Oct 29 '25 08:10 raphw