Reputation: 136
I am using ByteBuddy's @Advice
to transform my classes and it works fine until I try to replace input arguments.
I have a FooService
with a join
method which just joins two strings with a space.
public class FooService {
public String join(String message, String message1) {
return message + " " + message1;
}
}
And I have another method which takes a Object[] args
array input and changes elements in the array.
public static ArgsProcessor argsProcessor = args -> {
args[0] = args[0] + "-suffix";
args[1] = "replaced";
};
I've tried different ways to use the argsProcessor
to manipulate the input arguments in @Advice.OnMethodEnter
method. For me, the following advice implementations are almost equivalent and should all work, somehow only Advice1
works.
public static class Advice1 {
@Advice.OnMethodEnter
public static void onEnter(@Advice.AllArguments(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object[] args) {
Object[] newArgs = Arrays.copyOf(args, args.length);
ArgsProcessor argsProcessor = Demo.argsProcessor;
argsProcessor.process(newArgs);
args = newArgs;
}
}
public static class Advice2 {
@Advice.OnMethodEnter
public static void onEnter(@Advice.AllArguments(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object[] args) {
Object[] newArgs = new Object[args.length];
ArgsProcessor argsProcessor = Demo.argsProcessor;
argsProcessor.process(args);
System.arraycopy(args, 0, newArgs, 0, args.length);
args = newArgs;
}
}
public static class Advice3 {
@Advice.OnMethodEnter
public static void onEnter(@Advice.AllArguments(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object[] args) {
Object[] newArgs = Arrays.copyOf(args, args.length);
try {
ArgsProcessor argsProcessor = Demo.argsProcessor;
argsProcessor.process(newArgs);
args = newArgs;
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
public static class Advice4 {
@Advice.OnMethodEnter
public static void onEnter(@Advice.AllArguments(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object[] args) {
ArgsProcessor argsProcessor = Demo.argsProcessor;
argsProcessor.process(args);
}
}
public static class Advice5 {
@Advice.OnMethodEnter
public static void onEnter(@Advice.AllArguments(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object[] args) {
ArgsProcessor argsProcessor = Demo.argsProcessor;
argsProcessor.process(args);
args = Arrays.copyOf(args, args.length);
}
}
Output
Advice1 a-suffix replaced
Advice2 a b
Advice3 a b
Advice4 a b
Advice5 a b
The code snippet https://gist.github.com/raptium/ab7830e5d7f7cba43bbd2c2a5c7b38e0
Upvotes: 3
Views: 750
Reputation: 44032
Running your code, I get
Advice1 a-suffix replaced
Advice2 a b
Advice3 a-suffix replaced
Advice4 a b
Advice5 a b
what is what I expect. Byte Buddy uses advice methods as templates. This code is not really exeucted. When you read args
in your method, Byte Buddy creates a new array every time.
Therefore, computing args == args
would return false
since Byte Buddy creates a new array containing all arguments every time! If you change the args array, you have to write it back for Byte Buddy to discover the corresponding byte code and to map it back to an assignment.
Upvotes: 1