Reputation: 13
I encountered a problem while using Byte Buddy (a java agent lib) to replace a field, For example, the following example code:
public class A {
public static String foo;
public String originalMethod() {
return foo; // 'return dynamicGenerateMethod()' after replaced
}
public String dynamicGenerateMethod() {
return "bar";
}
}
When I use MemberSubstitution
to replace static field A.foo access with with a new generate method:
DynamicType.Unloaded<?> make = new ByteBuddy()
.redefine(A.class)
.defineMethod("dynamicGenerateMethod", String.class, Opcodes.ACC_PUBLIC)
.intercept(FieldAccessor.ofField("foo"))
.visit(MemberSubstitution.relaxed()
.field(named("foo"))
.onRead()
.replaceWithMethod(named("dynamicGenerateMethod"))
.on(not(named("dynamicGenerateMethod"))))
.make();
An exception is thrown:
java.lang.IllegalStateException: Cannot substitute parameterless instruction with public static java.lang.String com.test.A.foo
at net.bytebuddy.asm.MemberSubstitution$Substitution$ForMethodInvocation$MethodResolver$Matching.resolve(MemberSubstitution.java:1359)
If we remove the static decoration of foo, everything is normal.
I want to know if static variables cannot be replaced? Or is there a problem with my usage?
Upvotes: 1
Views: 79
Reputation: 44032
replaceWithMethod
looks for a non-static method that is declared by the instrumented class. If you want to locate a static method, specify it directly.
Otherwise, as foo
is static, you would need to specify a target manually as the parameters to the field read do not match. You can use a replaceWithChain
for this where you could insert a byte code instruction to load this
and then invoke a method on it:
DynamicType.Unloaded<?> make = new ByteBuddy()
.redefine(A.class)
.defineMethod("x", String.class, Opcodes.ACC_PUBLIC)
.intercept(FieldAccessor.ofField("foo"))
.visit(MemberSubstitution.relaxed()
.field(named("foo"))
.onRead()
.replaceWithChain(
new MemberSubstitution.Substitution.Chain.Step.Simple(
MethodVariableAccess.loadThis(),
A.class
),
new MemberSubstitution.Substitution.Chain.Step.ForInvocation.Factory(
A.class.getMethod("dynamicGenerateMethod")
)
)
.on(named("originalMethod")))
.make();
Upvotes: 0