raphw/byte-buddy

Error when trying to modify the response of a method assigned to a public static final config variable

Closed this issue · 9 comments

jdk corretto-17.0.7 , and bytebuddy version is 1.14.9

I get :

None of [public static java.lang.Object com.bcp.fraud.streams.Main$MyInterceptor.intercept(com.bcp.fraud.streams.Main$MyCallable,java.lang.Object[]) throws java.lang.Exception] allows for delegation from public static org.apache.kafka.common.config.ConfigDef io.confluent.kafka.schemaregistry.rest.SchemaRegistryConfig.baseSchemaRegistryConfigDef()

this is my code:

new AgentBuilder.Default()
.with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
.with(AgentBuilder.TypeStrategy.Default.REDEFINE)
.with(new FlowListener())
.ignore(nameStartsWith("net.bytebuddy."))
.type(ElementMatchers.named("io.confluent.kafka.schemaregistry.rest.SchemaRegistryConfig"))
.transform((builder, typeDescription, classLoader, module, protectionDomain) -> {
//return builder;
return builder
.method(named("baseSchemaRegistryConfigDef"))
.intercept(MethodDelegation.to(MyInterceptor.class));
})
.installOn(inst);

What I want is to modify a routine of that method in Java, what should I use?

I use net.bytebuddy.agent.ByteBuddyAgent.install method to instrumentation at runtime.

What's your interceptor class, including annotations and imports?

Hi , thanks for replying,
Is it technically possible to modify this method?
image

--> Code:
`import io.confluent.kafka.schemaregistry.rest.SchemaRegistryConfig;
import io.confluent.rest.RestConfigException;
import javassist.NotFoundException;
import net.bytebuddy.agent.ByteBuddyAgent;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.asm.MemberSubstitution;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.matcher.ElementMatchers;
import net.bytebuddy.utility.JavaModule;
import org.apache.kafka.common.config.ConfigDef;

import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;
import java.util.Properties;
import static net.bytebuddy.matcher.ElementMatchers.*;

public class MainX2 {

public static void main(String[] args) throws RestConfigException, NotFoundException {
    SchemaRegistryConfig test = new SchemaRegistryConfig(new Properties());
    Instrumentation instrumentation = ByteBuddyAgent.install();
    new AgentBuilder.Default()
            .with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
            .with(AgentBuilder.RedefinitionStrategy.REDEFINITION)
            .with(AgentBuilder.RedefinitionStrategy.Listener.StreamWriting.toSystemError())
            .with(AgentBuilder.Listener.StreamWriting.toSystemError().withTransformationsOnly())
            .with(AgentBuilder.InstallationListener.StreamWriting.toSystemError())
            .type(ElementMatchers.named("io.confluent.kafka.schemaregistry.rest.SchemaRegistryConfig"))
            .transform(new AgentBuilder.Transformer() {
                @Override
                public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription,
                                                        ClassLoader classLoader, JavaModule module, ProtectionDomain protectionDomain) {
                    try {
                        return builder
                                .visit(MemberSubstitution.strict()
                                        .method(named("baseSchemaRegistryConfigDef"))
                                        .replaceWith(MainX2.class.getMethod("baseSchemaRegistryConfigDef"))
                                        .on(any()));
                    } catch (NoSuchMethodException e) {
                        throw new RuntimeException(e);
                    }
                  
                }
            }).installOn(instrumentation);

    SchemaRegistryConfig teSchemaRegistryConfig = new SchemaRegistryConfig(new Properties());

    System.out.println(teSchemaRegistryConfig.baseSchemaRegistryConfigDef().configKeys().size());

}

public static ConfigDef baseSchemaRegistryConfigDef() {
    return new ConfigDef();
}

`
I would like to know if it is possible to replace the body of that method with a modified one. I have tried some examples but no success.

It is, but the static initializer will not be rerun on a retransformation. In this case, you would need to hook before the class is loaded for the first time.

I agree Rafael, with AgentBuilder could I achieve it?
If you have any reference it would help me a lot for what I am looking for

You mean rerun the static initializer? That is not possible, unfortunately, the JVM does not support it.

If I understood what you indicated... ("you would need to hook before the class is loaded for the first time.")
could you give me some reference on how I could resolve this case? thank you so much :)

@raphw
Could you just tell me which api to use?

You are doing it right, but there's nothing that can fix your problem if the initializer already ran.

Thank you very much for the support! , I found everything about bytebuddy interesting.