Как мне вызвать MethodCall с другим MethodCall для первого аргумента MethodCall? - PullRequest
2 голосов
/ 14 июля 2020

Я пытаюсь реализовать это:

@Override // java.util.Function
public Object apply(final ThingWithParameters thing) {
  return bozo(thing.getParameters());
}
private Object bozo(final Object[] parameters) {
  // Use magic ByteBuddy stuff to "spread" the parameters out
  return this.object.baz(parameter0, parameter1); // ...where these are the first two parameters in the array
}

Я пробовал:

builder = builder
  .defineMethod("bozo" ...)
  .implement(MethodCall.invoke(bazDescription)
             .onField(thisObjectFieldDescription)
             .withArgumentArrayElements(0, 2))

  .implement(parameterizedTypeFunctionThingWithParametersObject) // Function<ThingWithParameters, Object>
  .intercept(MethodCall.invoke(bozoDescription) // implement apply(ThingWithParameters thing): call bozo()...
             .withMethodCall(MethodCall.invoke(getParametersMethodDescription) // ...with the result of invoking getParameters()...
                             .onArgument(0))); // ...on thing (except see below)

… но это не работает. Сообщение об ошибке очень странное и заставляет меня думать, что аргумент 0 относится не к thing, а совсем к чему-то другому (может быть, тип получателя каким-то образом?). Вот фрагмент из стека:

java.lang.IllegalStateException: Cannot invoke public java.lang.Object[] com.foo.ThingWithParameters.getParameters() on java.util.function.Function<? super V, ? extends com.foo.ThingWithParameters>
    at net.bytebuddy.implementation.MethodCall$TargetHandler$ForMethodParameter$Resolved.toStackManipulation(MethodCall.java:2530)
    at net.bytebuddy.implementation.MethodCall$Appender.toStackManipulation(MethodCall.java:3548)
    at net.bytebuddy.implementation.MethodCall$ArgumentLoader$ForMethodCall.toStackManipulation(MethodCall.java:1687)
    at net.bytebuddy.implementation.MethodCall$Appender.toStackManipulation(MethodCall.java:3545)
    at net.bytebuddy.implementation.MethodCall$Appender.apply(MethodCall.java:3509)
    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)

Обратите внимание, что, хотя мой прокси-класс фактически реализует Function, он фактически реализует Function<ThingWithParameters, Object>. И я никогда не определяю V. Я предполагаю, что ByteBuddy делает это где-то внутри.

Какой рецепт мне следует использовать?

1 Ответ

1 голос
/ 16 июля 2020

Класс Function определяет несколько методов, некоторые из которых используются по умолчанию. Byte Buddy попытается реализовать все эти методы вашим Implementation, где он работает для apply метода, но не работает для других. Поэтому лучше определите явное сопоставление, чтобы указать метод, который вы хотите реализовать.

...