简体   繁体   English

使用 Byte Buddy 对参数进行强制转换调用方法

[英]Invoke method on a argument with a cast using Byte Buddy

I'm very new to Byte Buddy, and I'm trying to use it to create implementations of an interface that execute getter methods on objects.我对 Byte Buddy 很陌生,我正在尝试使用它来创建在对象上执行 getter 方法的接口的实现。 My interface looks like this:我的界面是这样的:

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

And the idea is that if I have a class such as:这个想法是,如果我有一个类,例如:

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

I need to be able to create one implementation of the Executor interface which execute(obj) method assumes obj is a User and calls its getName() , then another implementation which does the same for getSurname() , etc. Equivalent java code would therefore be:我需要能够创建Executor接口的一个实现,其中execute(obj)方法假定obj是一个User并调用它的getName() ,然后另一个实现对getSurname()等执行相同的getSurname() 。因此等效的 java 代码将是:

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

So the idea is to be able to create classes like the above for any combination of class + getter, like in this case User + getName() .所以我们的想法是能够为类 + getter 的任何组合创建像上面这样的类,就像在这种情况下User + getName()

I (think I) know how to make Byte Buddy create a class that almost does that:我(认为我)知道如何让 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();

...but then Byte Buddy rightly throws an Exception saying that I cannot execute method getName() on an Object . ...但随后 Byte Buddy 正确地抛出了一个 Exception 说我不能在Object上执行方法getName() I'm assuming therefore that I'm lacking the ((User) target) cast:因此,我假设我缺少((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)
    ...

I believe this could be defined as a StackManipulation (I might be totally wrong), something like:我相信这可以定义为StackManipulation (我可能完全错了),例如:

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

But I cannot find anywhere in the Byte Buddy API how I can apply this cast (or any other code I might need for casting) to the argument of the execute(Object) method before executing the getter.但是我无法在 Byte Buddy API 中的任何地方找到如何在执行 getter 之前将此转换(或我可能需要转换的任何其他代码)应用于execute(Object)方法的参数。

How can I implement this?我该如何实施?

This should work by using dynamic typing which you can configure by:这应该通过使用动态类型来工作,您可以通过以下方式进行配置:

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

The stack manipulation is used for creating custom byte code, I do not think that this is what you want to do here.堆栈操作用于创建自定义字节码,我认为这不是您在这里要做的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM