问题描述
我知道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方法命名(出于各种原因)。我将target
和parameters
都接受了,然后使用提供的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
的大小为parameters
。 2
的大小为pip install
。
我在做什么错了?
解决方法
此处的维护器:确实是一个错误,在循环内重复了增量。这将在1.10.15版中修复。
,我了解到,如果您的接收方方法具有多个参数,则您必须使用withArgumentArrayElements
的两个或三个参数的变体。 one-argument variant似乎只能用于具有零参数或一个参数的接收器方法。