Как заменить входные аргументы с помощью ByteBuddy @ Advice.AllArguments? - PullRequest
1 голос
/ 29 мая 2020

Я использую 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

1 Ответ

1 голос
/ 30 мая 2020

Запустив ваш код, я получаю

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 обнаружил соответствующий байтовый код и сопоставил его с назначением.

...