首页 > 解决方案 > 如何使用 ByteBuddy 的 @Advice.AllArguments 替换输入参数?

问题描述

我正在使用 ByteBuddy@Advice来转换我的类,它工作正常,直到我尝试替换输入参数。

我有一个FooService使用join空格连接两个字符串的方法。

public class FooService {
    public String join(String message, String message1) {
        return message + " " + message1;
    }
}

我还有另一种方法,它接受Object[] args数组输入并更改数组中的元素。

    public static ArgsProcessor argsProcessor = args -> {
        args[0] = args[0] + "-suffix";
        args[1] = "replaced";
    };

我尝试了不同的方法来使用argsProcessor来操作方法中的输入参数@Advice.OnMethodEnter。对我来说,以下建议的实现几乎是等效的,应该都可以工作,但只能Advice1工作。

    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);
        }
    }

输出

Advice1 a-suffix replaced
Advice2 a b
Advice3 a b
Advice4 a b
Advice5 a b

代码片段https://gist.github.com/raptium/ab7830e5d7f7cba43bbd2c2a5c7b38e0

标签: javabyte-buddy

解决方案


运行你的代码,我明白了

Advice1 a-suffix replaced 
Advice2 a b 
Advice3 a-suffix replaced 
Advice4 a b 
Advice5 a b

我的期望是什么。Byte Buddy 使用建议方法作为模板。这段代码并没有真正执行。当您阅读args您的方法时,Byte Buddy每次都会创建一个新数组

因此,计算args == args将返回,false因为 Byte Buddy 每次都会创建一个包含所有参数的新数组!如果更改 args 数组,则必须将其写回以供 Byte Buddy 发现相应的字节码并将其映射回分配。


推荐阅读