使用Byte Buddy对类型进行参数调用的方法

时间:2019-04-04 10:23:18

标签: java code-generation introspection byte-buddy

我是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)方法假定objUser并调用其getName(),然后对getSurname()等执行相同操作的另一个实现。因此,等效的Java代码为:

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

因此,我们的想法是能够为class + getter的任何组合创建类似于上述的类,例如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();

...但是随后字节好友正确抛出了一个异常,表明我无法在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));

但是我无法在Byte Buddy API的任何地方找到如何在执行getter之前将这种强制转换(或可能需要强制转换的任何其他代码)应用于execute(Object)方法的参数的方法。

我该如何实现?

1 个答案:

答案 0 :(得分:1)

这应该通过使用动态类型来实现,您可以通过以下方式进行配置:

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

堆栈操作用于创建自定义字节码,我不认为这是您要在此处执行的操作。