Вызвать метод для аргумента с приведением, используя Byte Buddy - PullRequest
2 голосов
/ 04 апреля 2019

Я очень новичок в Byte Buddy, и я пытаюсь использовать его для создания реализаций интерфейса, который выполняет методы getter для объектов.Мой интерфейс выглядит следующим образом:

public interface Executor {
    Object execute(final Object target);
}

И идея в том, что если у меня есть такой класс, как:

public class User {
   ...
   public String getName() { return this.name; }
   public String getSurname() { return this.surname; }
}

, мне нужно иметь возможность создать одну реализацию Executor интерфейс, который execute(obj) метод предполагает, что obj является User и вызывает его getName(), затем другая реализация, которая делает то же самое для getSurname() и т. д. Эквивалентный код Java, следовательно, будет:

public class MyHypotheticalByteBuddyExecutorImpl implements Executor {
    @Override
    Object execute(final Object target) {
        return ((User) target).getName();
    }
}

Таким образом, идея состоит в том, чтобы иметь возможность создавать классы, подобные описанным выше, для любой комбинации класс + геттер, как в этом случае User + getName().

Я (думаю, я) знаю, какЗаставьте Byte Buddy создать класс, который почти делает это:

final Method nameMethod = User.class.getMethod("getName", null);

final Class<?> myHypotheticalByteBuddyExecutorImpl =
    new ByteBuddy()
        .subclass(Object.class)
        .implement(Executor.class)
        .method(ElementMatchers.named("execute"))
            .intercept(MethodCall.invoke(nameMethod).onArgument(0))
        .make()
        .load(ByteBuddyTest.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
        .getLoaded();

... но затем Byte Buddy справедливо создает исключение, говоря, что я не могу выполнить метод getName() для Object.Поэтому я предполагаю, что мне не хватает ((User) target) приведения:

Exception in thread "main" java.lang.IllegalStateException: Cannot invoke public java.lang.String com.example.User.getName() on class java.lang.Object
    at net.bytebuddy.implementation.MethodCall$TargetHandler$ForMethodParameter$Resolved.toStackManipulation(MethodCall.java:2527)
    at net.bytebuddy.implementation.MethodCall$Appender.toStackManipulation(MethodCall.java:3541)
    at net.bytebuddy.implementation.MethodCall$Appender.apply(MethodCall.java:3502)
    ...

Я считаю, что это можно определить как StackManipulation (я могу быть совершенно неправ), что-то вроде:

final StackManipulation typeCasting =
    TypeCasting.to(TypeDescription.ForLoadedType.of(User.class));

Но я не могу найти где-нибудь в API-интерфейсе Byte Buddy, как я могу применить это приведение (или любой другой код, который мне может понадобиться для приведения) к аргументу метода execute(Object) перед выполнением метода получения.

Как я могу это реализовать?

1 Ответ

1 голос
/ 05 апреля 2019

Это должно работать с использованием динамической типизации, которую вы можете настроить следующим образом:

MethodCall.invoke(nameMethod)
  .onArgument(0)
  .withAssigner(Assigner.DEFAULT, Assigner.Typing.DYNAMIC);

Управление стеками используется для создания пользовательского байтового кода, я не думаю, что это то, что вы хотите сделать здесь.

...