如何使用Byte-buddy重新定义一个类以添加额外的方法。

huangapple go评论61阅读模式
英文:

How to redefine a class with Byte-buddy to add an additional method

问题

You are trying to use ByteBuddy to redefine the Dog class and add a getAge method. Here's the corrected code for your Attempt 1:

new AgentBuilder.Default()
    .type(ElementMatchers.named("Dog"))
    .transform((builder, typeDescription, classLoader, module) ->
        builder.defineMethod("getAge", int.class, Modifier.PUBLIC)
               .intercept(MethodDelegation.to(PitBullInterceptor.class))
    )
    .installOn(instrumentation);

This code snippet uses the ElementMatchers to identify the Dog class, then defines the getAge method and delegates its execution to the PitBullInterceptor class.

Make sure to import the necessary classes and adjust any other parts of your code as needed. This should help you redefine the Dog class with the desired getAge method.

英文:

If I have the following Class named Dog

public class Dog {
  
  private String name = "Spike";
  private int age = 3;
  
  public Dog() {}
  
  public String getName() {
    return name;
  }
}

How would I declare ByteBuddy for use in a javaagent to redefine the Dog class to provide the method getAge which returns an int?

The desired (effective) class should look like this below and be able to be invoked by doing dog.getAge()

public class Dog {
  
  private String name = "Spike";
  private int age = 3;
  
  public Dog() {}
  
  public String getName() {
    return name;
  }

  public int getAge() {
    return age;      
  }
}

Attempt 1: I've tried changing the syntax to what I understand to be correct (PitBullInterceptor.class found below)

new AgentBuilder.Default()
.redefine(Dog.class)
.defineMethod("getAge", int.class, Method.PUBLIC)
.intercept(MethodDelegation.to(PitBullInterceptor.class))
.installOn(instrumentation);

I have the following issue in my attempts

> The method redefine(Class<Dog>) is undefined for the type
> AgentBuilder.Default

Which is basically a syntax error. I'm not sure which DynamicTypes or MethodDelegations/ElementMaters to use to configure the Agentbuilder to perform to this type of redefine/rebase as Rafael Winterhalter describes it

Attempt 2: I've tried using it with ByteBuddyAgent.install

  public static void main(String[] args) throws Exception {
    
    ByteBuddyAgent.install();
    
    new ByteBuddy()
    .redefine(Dog.class)               
    .defineMethod(&quot;getAge&quot;, int.class, Method.PUBLIC)
    .intercept(MethodDelegation.to(PitBullInterceptor.class))
    .make()
    .load(Dog.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent())
    .getLoaded()
    .newInstance();
  }
  
  public static class PitBullInterceptor {
    
    private static int age = 1;
    
    public static int getAge() {
      return age;
    }
  }

Produces the error:

> java.lang.UnsupportedOperationException: class redefinition failed: attempted to add a method

Attempt 3: Lastly, I've tried doing so with the agent built

  public static void premain(String arguments, Instrumentation instrumentation) {
  
    new AgentBuilder.Default()
    .disableClassFormatChanges().with(RetransformationStrategy.RETRANSFORM)
    .with(new ByteBuddy()
    .redefine(PitBull.class)
    .method(ElementMatchers.named(&quot;getAge&quot;))
    .intercept(MethodDelegation.to(PitBullInterceptor.class))
    .make()
    .load(Dog.class.getClassLoader()))
    .installOn(instrumentation);
  }
  
  public static class PitBull {
    
    private String name = &quot;Kujo&quot;;
    
    public String getName() {
      return name;
    }
  }
  
  public static class PitBullInterceptor {
    
    private static int age = 3;
    
    public static int getAge() {
      return age;
    }
  }

Produces:

java -javaagent:agent.jar -jar app.jar
Exception in thread &quot;main&quot; java.lang.reflect.InvocationTargetException
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:568)
        at java.instrument/sun.instrument.InstrumentationImpl.loadClassAndStartAgent(InstrumentationImpl.java:491)
        at java.instrument/sun.instrument.InstrumentationImpl.loadClassAndCallPremain(InstrumentationImpl.java:503)
Caused by: java.lang.IllegalStateException: Class already loaded: class io.xxx.agent.boss.Agent$PitBull
        at net.bytebuddy.dynamic.loading.ByteArrayClassLoader.load(ByteArrayClassLoader.java:363)
        at net.bytebuddy.dynamic.loading.ClassLoadingStrategy$Default$WrappingDispatcher.load(ClassLoadingStrategy.java:367)
        at net.bytebuddy.dynamic.loading.ClassLoadingStrategy$Default.load(ClassLoadingStrategy.java:148)
        at net.bytebuddy.dynamic.TypeResolutionStrategy$Passive.initialize(TypeResolutionStrategy.java:101)
        at net.bytebuddy.dynamic.DynamicType$Default$Unloaded.load(DynamicType.java:6317)
        at net.bytebuddy.dynamic.DynamicType$Default$Unloaded.load(DynamicType.java:6305)
        at io.xxx.agent.boss.Agent.premain(Agent.java:21)
        ... 6 more
*** java.lang.instrument ASSERTION FAILED ***: &quot;result&quot; with message agent load/premain call failed at t:\workspace\open\src\java.instrument\share\native\libinstrument\JPLISAgent.c line: 422
FATAL ERROR in native method: processing of -javaagent failed, processJavaStart failed

答案1

得分: 1

由于JVM的限制,您无法添加、删除或修改现有类的成员。您只能:

  1. 在加载类之前添加方法,或者
  2. 在JVM启动之前修改磁盘上的类

或者,您可以使用支持这种修改的第三方JVM(请参阅:带有增强类重新定义标志的JetBrains运行时),但假设需要在各种情况下运行,这可能会有些繁琐。

英文:

Due to limitations of the JVM, you can't add, remove or modify members of existing classes. You have to either

  1. Add the method before the class is loaded, or
  2. Modify the class on disk before the JVM even starts

Alternatively, you could use third party JVMs that do support that kind of modification (see: JetBrains runtime with the Enhanced class redefinition flag), but assuming this needs to run universally, it'd be a bit of a burden.

huangapple
  • 本文由 发表于 2023年5月7日 07:19:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/76191595.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定