使用 Byte Buddy 对带有强制转换的参数调用方法
Invoke method on a argument with a cast using Byte Buddy
我是 Byte Buddy 的新手,我正在尝试使用它来创建对对象执行 getter 方法的接口的实现。我的界面如下所示:
public interface Executor {
Object execute(final Object target);
}
我的想法是,如果我有一个 class 例如:
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();
}
}
所以我们的想法是能够为 class + getter 的任意组合创建像上面那样的 classes,就像在这种情况下 User
+ getName()
.
我(认为我)知道如何让 Byte Buddy 创建一个几乎可以做到这一点的 class:
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 正确地抛出了一个异常,说我无法在 Object
上执行方法 getName()
。因此,我假设我缺少 ((User) target)
cast:
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.
我该如何实现?
这应该通过使用动态类型来工作,您可以通过以下方式进行配置:
MethodCall.invoke(nameMethod)
.onArgument(0)
.withAssigner(Assigner.DEFAULT, Assigner.Typing.DYNAMIC);
堆栈操作用于创建自定义字节码,我认为这不是您想在这里做的。
我是 Byte Buddy 的新手,我正在尝试使用它来创建对对象执行 getter 方法的接口的实现。我的界面如下所示:
public interface Executor {
Object execute(final Object target);
}
我的想法是,如果我有一个 class 例如:
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();
}
}
所以我们的想法是能够为 class + getter 的任意组合创建像上面那样的 classes,就像在这种情况下 User
+ getName()
.
我(认为我)知道如何让 Byte Buddy 创建一个几乎可以做到这一点的 class:
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 正确地抛出了一个异常,说我无法在 Object
上执行方法 getName()
。因此,我假设我缺少 ((User) target)
cast:
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.
我该如何实现?
这应该通过使用动态类型来工作,您可以通过以下方式进行配置:
MethodCall.invoke(nameMethod)
.onArgument(0)
.withAssigner(Assigner.DEFAULT, Assigner.Typing.DYNAMIC);
堆栈操作用于创建自定义字节码,我认为这不是您想在这里做的。