简体   繁体   中英

How to call a Clojure variadic function from Java

Is it possible to declare a variadic function in Clojure that can be called as a varargs method from Java?

Consider this extract from some code under development:

(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)))

Is there anything I can put in place of ????? to allow Java to call the exprFactory method and to know that it is a varargs method:

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);

To make this a little clearer, I know I use Object in place of ????? and change exprFactory to:

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

..but that means I have to write Java calls like this:

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 }));

Again, I know I could write a varargs wrapper method in Java that calls the non-variadic exprFactory , but I'd like to avoid that if possible.

I would suggest writing your helper function on the Java side, something like the "applyToHelper" in clojure.lang.AFn

This would take the form of a Java function that looks something like:

   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
     }
   }

It's a bit of a hack and depends on the internal definition of clojure.lang.IFn , but at least you will get relatively nice variadic syntax on the Java side (ie no need to do the new Object[] {...} stuff).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM