Как вызвать вариационную функцию Clojure из Java

Можно ли объявить переменную функцию в Clojure, которую можно вызывать как метод varargs из Java?

Рассмотрим этот фрагмент из некоторого кода, находящегося в разработке:

(ns com.mydomain.expression.base 
  (:gen-class
    :name com.mydomain.expression.Base
    :methods [^:static [exprFactory [String String ?????] Object]]
  )

(defn expr-factory
  ; worker function that is also called from Clojure
  [id func & args]
  (let [ex ("construction code here")]
    ex))

(defn -exprFactory
  ; interface method called from Java
  [idStr funcStr & argsArray]
  (apply expr-factory idStr funcStr (seq argsArray)))

Есть ли что-нибудь, что я могу поставить вместо ?????, чтобы позволить Java вызывать метод exprFactory и знать, что это метод varargs:

import com.mydomain.expression.Base;
...
Object e1 = Base.exprFactory("e1", "day");
Object e2 = Base.exprFactory("e2", "length", "string");
Object e3 = Base.exprFactory("e3", "*", 4, 5);
Object sum = Base.exprFactory("sum", "+", e1, e2, e3);

Чтобы сделать это немного яснее, я знаю, что вместо ????? вместо ????? использую Object и изменяю exprFactory на:

(defn -exprFactory
  ; interface method called from Java
  [idStr funcStr argsArray]
  (apply expr-factory idStr funcStr (seq argsArray)))

.. но это означает, что я должен написать Java-вызовы следующим образом:

import com.mydomain.expression.Base;
...
Object e1 = Base.exprFactory("e1", "day", new Object[0] ));
Object e2 = Base.exprFactory("e2", "length", new Object[] { "string" }));
Object e3 = Base.exprFactory("e3", "*", new Integer[] { 4, 5 }));
Object sum = Base.exprFactory("sum", "+", new Object[] { e1, e2, e3 }));

Опять же, я знаю, что могу написать метод оболочки varargs в Java, который вызывает невариантный exprFactory, но я хотел бы избежать этого, если это возможно.

Ответ 1

Я бы предложил написать вашу вспомогательную функцию на стороне Java, что-то вроде "applyToHelper" в clojure.lang.AFn

Это будет выглядеть как функция Java, которая выглядит примерно так:

   public Object invokeVariadic(IFn function, Object... args) {
     switch (args.length) {
       case 0:
         return function.invoke();
       case 1:
         return function.invoke(args[0]);
       /// 20-odd more cases
     }
   }

Это немного взломать и зависит от внутреннего определения clojure.lang.IFn, но по крайней мере вы получите относительно хороший вариационный синтаксис на стороне Java (т.е. не нужно делать вещи new Object[] {...}).