英文:
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("getAge", 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("getAge"))
.intercept(MethodDelegation.to(PitBullInterceptor.class))
.make()
.load(Dog.class.getClassLoader()))
.installOn(instrumentation);
}
public static class PitBull {
private String name = "Kujo";
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 "main" 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 ***: "result" 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的限制,您无法添加、删除或修改现有类的成员。您只能:
- 在加载类之前添加方法,或者
- 在JVM启动之前修改磁盘上的类
或者,您可以使用支持这种修改的第三方JVM(请参阅:带有增强类重新定义标志的JetBrains运行时),但假设需要在各种情况下运行,这可能会有些繁琐。
英文:
Due to limitations of the JVM, you can't add, remove or modify members of existing classes. You have to either
- Add the method before the class is loaded, or
- 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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论