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

redefine for java.time.Clock#instant not work with jdk 17 runtime

Open lossend opened this issue 5 months ago • 6 comments

jvm runtime: openjdk17 bytebudy version: 1.14.3

i tried to interrupt " java.time.Clock#instant" method with below code, but it did not work?

   new AgentBuilder.Default()
                .disableClassFormatChanges()
                .ignore(nameStartsWith("net.bytebuddy."))
                .with(new TransformListener())
                .with(new ByteBuddy().with(Implementation.Context.Disabled.Factory.INSTANCE))
                .with(AgentBuilder.InitializationStrategy.NoOp.INSTANCE)
                .with(AgentBuilder.RedefinitionStrategy.REDEFINITION)
                .with(AgentBuilder.TypeStrategy.Default.REDEFINE)
                .type(hasSuperClass(ElementMatchers.named("java.time.Clock")))
                .transform((builder, typeDescription, classLoader, module, protectionDomain) -> builder
                        .method(ElementMatchers.named("instant"))
                        .intercept(Advice.to(ClockInterceptor.class).wrap(StubMethod.INSTANCE)))
                .installOn(inst);

ClockInterceptor code is:

@Slf4j
public class ClockInterceptor {

    @Advice.OnMethodExit(suppress = Throwable.class)
    public static void onExit(@Advice.Return(readOnly = false, typing = Assigner.Typing.DYNAMIC) Instant result) {
        if (ClockMockDispatcher.dispatcher != null) {
            long mockMillis = ClockMockDispatcher.dispatcher.mockMillis();
            if (mockMillis > 0) {
                result = Instant.ofEpochMilli(mockMillis);
            }
        }
    }
}

lossend avatar Jul 30 '25 08:07 lossend

Apply Advice as a visitor:

builder.visit(Advice.to(ClockInterceptor.class).on(ElementMatchers.named("instant"))

raphw avatar Jul 30 '25 08:07 raphw

Apply Advice as a visitor:

builder.visit(Advice.to(ClockInterceptor.class).on(ElementMatchers.named("instant"))

it works, but why? i'm new to bytebuddy

lossend avatar Jul 30 '25 08:07 lossend

If you apply advice as a visitor, it simply decorates existing methods. The class file as such remains intact, however.

If you apply it as an interceptor, it replaces the current method with a new implementation. This is a more powerful concept, and allows more adjustments, but is also requiring some changes to the class file. This is not allowed (by the JVM) for retransformations.

raphw avatar Jul 30 '25 08:07 raphw

If you apply advice as a visitor, it simply decorates existing methods. The class file as such remains intact, however.

If you apply it as an interceptor, it replaces the current method with a new implementation. This is a more powerful concept, and allows more adjustments, but is also requiring some changes to the class file. This is not allowed (by the JVM) for retransformations.

  1. but the old code did work in jdk 8?
  2. when i rewrite with AgentBuilder.TypeStrategy.Default.REBASE, it does not work too
 new AgentBuilder.Default()
                .disableClassFormatChanges()
                .ignore(nameStartsWith("net.bytebuddy."))
                .with(new TransformListener())
                .with(new ByteBuddy().with(Implementation.Context.Disabled.Factory.INSTANCE))
                .with(AgentBuilder.InitializationStrategy.NoOp.INSTANCE)
                .with(AgentBuilder.RedefinitionStrategy.REDEFINITION)
                .with(AgentBuilder.TypeStrategy.Default.REBASE)
                .type(hasSuperClass(ElementMatchers.named("java.time.Clock")))
                .transform((builder, typeDescription, classLoader, module, protectionDomain) -> builder
                        .method(ElementMatchers.named("instant"))
                        .intercept(Advice.to(ClockInterceptor.class)))
                .installOn(inst);

lossend avatar Jul 30 '25 09:07 lossend

Yes, you override settings from disableClassFormatChanges() doing so.

If the class is not loaded in JDK 8 before your agent gets active, it will work, but this you cannot rely on.

raphw avatar Jul 30 '25 11:07 raphw

I assume that the JDK did not load the Java class implicitly prior to the agent booting.

raphw avatar Jul 30 '25 13:07 raphw