ByteBuddy在方法的参数上“扩展”对象数组的能力有哪些限制?

问题描述

我知道MethodCall#withArgumentArrayElements(int)方法。简而言之,它允许您接受Object[]调用其他方法,并从Object[]参数标识的int开始按顺序提供其参数。通常,您还使用动态分配器。

我发现一个奇怪的局限性似乎不起作用。我想了解我做错了什么,或者ByteBuddy中是否有(罕见)问题。

我已经使用ByteBuddy生成一个static方法,其Java代码如下所示:

private static final void setFrob(final T target,final Object... parameters) throws Exception {
  target.setFrob((String)parameters[0],(Integer)parameters[1]); // pseudocode; happens via "spreading" mentioned above
}

我希望您能看到的模式是,在我所检测的类中,我定义了一个private static setter方法,该方法以“真实” setter方法命名(出于各种原因)。我将targetparameters都接受了,然后使用提供的target数组在parameters调用final MethodDescription staticSetterMethod = new MethodDescription.Latent(builder.toTypeDescription(),methodToken.getName(),PRIVATE_STATIC_FINAL_SYNTHETIC_VaraRGS_METHOD_MODIFIERS,Collections.emptyList(),TypeDescription.Generic.VOID,List.of(new ParameterDescription.Token(targettype,"target",ParameterManifestation.FINAL.getMask()),new ParameterDescription.Token(OBJECT_ARRAY_TYPE_DESCRIPTION_GENERIC,"parameters",ParameterManifestation.FINAL.getMask())),Collections.singletonList(EXCEPTION_TYPE_GENERIC),null,null); builder = builder .define(staticSetterMethod) 的“ real” setter方法,该数组为“实际”设置方法的参数。这并不复杂并且可以正常工作,但有趣的是,仅在某些情况下。

方法定义的ByteBuddy配方为:

javap

由于事情在某些情况下可行,因此我能够MethodCall.invoke(new MethodDescription.Latent(targettype.asErasure(),// T's actual type methodToken)) // setFrob(String,Integer) .onArgument(0) // target (of type T) .withArgumentArrayElements(1) // parameters .withAssigner(Assigner.DEFAULT,Assigner.Typing.DYNAMIC)); 生成结果类,并且方法定义与我期望的一样。我不担心这部分。

接下来,ByteBuddy实现食谱如下(我尝试使其简短而相关):

setFrob

…如此:在第一个自变量(target)上,传播传入的{{1},调用methodToken描述的target类型声明的Object[],由parameters描述}}使用动态分配在第二个参数(setFrob)中找到的数组值。

我的理解是,如果“真实的” String方法需要提供一个Integer一个Object[],那么如果此处的String长两个元素,如果第一个元素是Integer,第二个元素是withArgumentArrayElements(1),则setFrob调用将确保这些元素被“扩展”为适当的方法参数。 / p>

实际上,当被调用String方法接受零个或一个参数(假设它被定义为仅接受setFrob参数)时,此方法工作正常。那告诉我至少我的ByteBuddy食谱是正确的。

但是,我非常惊讶地注意到,调用java.lang.IllegalStateException: public void com.foo.bar.TestExplorations$Foo.setFrob(java.lang.String,java.lang.Integer) does not accept 1 arguments at net.bytebuddy.implementation.MethodCall$Appender.toStackManipulation(MethodCall.java:3539) at net.bytebuddy.implementation.MethodCall$Appender.apply(MethodCall.java:3508) at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod$WithBody.applyCode(TypeWriter.java:708) at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod$WithBody.applyBody(TypeWriter.java:693) at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod.apply(TypeWriter.java:600) at net.bytebuddy.dynamic.scaffold.TypeWriter$Default$ForCreation.create(TypeWriter.java:5660) at net.bytebuddy.dynamic.scaffold.TypeWriter$Default.make(TypeWriter.java:2166) at net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder.make(SubclassDynamicTypeBuilder.java:232) at net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder.make(SubclassDynamicTypeBuilder.java:204) 方法更改为接受两个参数时,它会失败。部分堆栈说:

ParameterList<?> parameters = invokedMethod.getParameters();
if (parameters.size() != argumentLoaders.size()) {
  throw new IllegalStateException(invokedMethod + " does not accept " + argumentLoaders.size() + " arguments");
}

错误是由this conditional引起的:

argumentLoaders

在这种情况下,1的大小为parameters2的大小为pip install

我在做什么错了?

解决方法

此处的维护器:确实是一个错误,在循环内重复了增量。这将在1.10.15版中修复。

,

我了解到,如果您的接收方方法具有多个参数,则您必须使用withArgumentArrayElements的两个或三个参数的变体。 one-argument variant似乎只能用于具有零参数或一个参数的接收器方法。