Я пытаюсь заменить отражающий вызов на MethodHandle, но с varargs, похоже, невозможно справиться.
Мой отражатель на данный момент выглядит так:
public class Invoker {
private final Method delegate;
public Invoker(Method delegate) {
this.delegate = delegate;
}
public Object execute(Object target, Object[] args) {
return delegate.invoke(target, args);
}
}
Моя текущая попытка переписать выглядит следующим образом (интерфейс, который выставляет Invoker
, должен остаться прежним):
public class Invoker {
private final Method delegate;
private final MethodHandle handle;
public Invoker(Method delegate) {
this.delegate = delegate;
this.handle = MethodHandles.lookup().unreflect(delegate);
}
public Object execute(Object target, Object[] args) throws InvocationTargetException, IllegalAccessException {
Object[] allArgs = Stream.concat(Stream.of(target), Stream.of(args)).toArray(Object[]::new);
return handle.invokeWithArguments(allArgs);
}
}
И это прекрасно работает в большинстве случаев. Но варагги все ломают.
Например. есть метод как:
public String test(int i, String... args) {
return ...;
}
А аргументы вроде:
Object[] args = new Object[] {10, new String[] {"aaa", "bbb"}};
И execute
, как реализовано выше, потерпит неудачу. Я пробовал различные комбинации asSpreader()
, MethodHandles.explicitCastArguments()
, invoke
вместо invokeWithArguments
и т. Д., Но безуспешно.
Единственный способ, которым я могу вызвать метод varargs, - предоставить аргументы inline, а не как массив. Э.Г.
handle.invokeWithArguments(10, "aaa", "bbb")
но я не могу этого сделать и поддерживать общий характер Invoker
, который у него есть в настоящее время.
Неужели это невозможно сделать так, как я пытаюсь?
UPDATE:
После сравнительного анализа различных сценариев я решил придерживаться рефлексии, так как invokeWithArguments
работает значительно хуже во всех тестированных случаях.