raphw / byte-buddy

Runtime code generation for the Java virtual machine.
https://bytebuddy.net
Apache License 2.0
6.23k stars 804 forks source link

Can 'private final method' in 'public final class' be redefined? #1591

Closed zzhlhc closed 7 months ago

zzhlhc commented 7 months ago

Sorry for asking such a simple question, but I really couldn't find the relevant answer.

Below is my current code:

public class DispatcherDelegation {
    public static Boolean promoteAndExecute(@This Dispatcher dispatcher){.....}
}

public class AgentMain {
   void redefineDispatcher(Instrumentation instrumentation) {
        byte[] newBytes = new ByteBuddy()
                .redefine(Dispatcher.class)
                .method(named("promoteAndExecute"))
                .intercept(MethodDelegation.to(DispatcherDelegation.class))
                .make()
                .getBytes();
        ClassDefinition classDefinition = new ClassDefinition(Dispatcher.class, newBytes);
        instrumentation.redefineClasses(classDefinition);
  }
}

Error is:

Caused by: java.lang.IllegalArgumentException: None of [public static java.lang.Boolean org.example.DispatcherDelegation.promoteAndExecute(...)] allows for delegation from private final boolean okhttp3.Dispatcher.promoteAndExecute()

How can I solve this problem? thank you very much! orz...

raphw commented 7 months ago

Can you show your imports? I wonder if you imported the Advice version.

zzhlhc commented 7 months ago

Sure, DispatcherDelegation's imports :

import net.bytebuddy.implementation.bind.annotation.FieldValue;
import net.bytebuddy.implementation.bind.annotation.This;
import okhttp3.Dispatcher;
import okhttp3.internal.connection.RealCall;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;

AgentMain's imports:

import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.dynamic.scaffold.TypeValidation;
import net.bytebuddy.implementation.MethodDelegation;
import okhttp3.Dispatcher;
import okhttp3.internal.connection.RealCall;

import java.lang.instrument.ClassDefinition;
import java.lang.instrument.Instrumentation;
import java.lang.instrument.UnmodifiableClassException;

import static net.bytebuddy.matcher.ElementMatchers.named;

byte-buddy's version:

<dependency>
            <groupId>net.bytebuddy</groupId>
            <artifactId>byte-buddy</artifactId>
            <version>1.11.22</version>
        </dependency>
zzhlhc commented 7 months ago

Solved, from your reply I realized that it might be a problem with the method parameters, deleted the executorService below, and succeeded

public class DispatcherDelegation {
      public static Boolean promoteAndExecute(@This Dispatcher dispatcher
                , @FieldValue("executorService") ExecutorService executorService)
}

The executorService in Dispatcher.kt:

  private var executorServiceOrNull: ExecutorService? = null

  @get:Synchronized
  @get:JvmName("executorService") val executorService: ExecutorService
    get() {
      if (executorServiceOrNull == null) {
        executorServiceOrNull = ThreadPoolExecutor(0, Int.MAX_VALUE, 60, TimeUnit.SECONDS,
            SynchronousQueue(), threadFactory("$okHttpName Dispatcher", false))
      }
      return executorServiceOrNull!!
    }

I'm new to both byte-buddy and kotlin, anyway the problem is solved, thanks!!

raphw commented 7 months ago

I think the field is executorServiceOrNull, the other one is the method. so you'd use rhe first as field name.