Java – > Clojure – > Java

我试图使用Clojure作为主机Java程序的脚本语言.这个想法是最终用户将能够编写将调用特定于域的Java API的Clojure脚本代码.在运行时,主机Java程序将评估最终用户的Clojure脚本(它将依次调用域API).所以我开始用一个简单的原型来探索地形.

package a.problem.domain;

public class Domain {

    public Domain() { }

    public String defaultMsg() {
        return "default";
    }

    public String passBackMsg(String s) {
        return s;
    }
}

主机Java程序

(为简单起见,最终用户的Clojure脚本硬编码)

String script = "(do                                    "+
                "  (import '(a.problem.domain Domain))  "+
                "  (.defaultMsg (Domain.))              "+
                ")                                      ";
System.out.println(RT.var("clojure.core", "eval").invoke(RT.var("clojure.core","read-string").invoke(script)));

(摘自here的代码段)

到现在为止还挺好.

但是我找不到调用第二种方法(需要参数的方法)的方法.相反,我使用在运行时动态生成Clojure脚本并用表示调用域方法passBackMsg的结果的文字替换占位符.显然,这是不能令人满意的,并没有走得太远(如果我想将java.sql.Connection传递给我的Clojure脚本怎么办?).

那么,我如何从宿主Java程序调用passBackMsg方法呢?

当我尝试以下内容时:

String script = "(ns foo)                                   "+ 
                "(import '(a.problem.domain Domain))        "+
                "(defn numberToString [s]  (                "+
                "  (.passBackMsg (Domain.) s)               "+
                "))                                         ";
RT.var("clojure.core", "eval").invoke(RT.var("clojure.core","read-string").invoke(script)); // line-A
System.out.println(RT.var("foo", "numberToString").invoke(33)); // line-B

我明白了:

java.lang.IllegalStateException: Can't change/establish root binding of: *ns* with set

……在A线上.当我尝试没有ns并且:

RT.var("user", "numberToString").invoke(33)

(“用户”是一个疯狂的猜测,因为我没有看到没有命名空间参数的var方法)

我得到一个:

java.lang.IllegalStateException: Attempting to call unbound fn: #'user/numberToString"

……在B线上.

最佳答案
试试这个:

String script = "(do                                    "+
                "  (import '(a.problem.domain Domain))  "+
                "  (fn [s]                " +
                "   (.passBackMsg (Domain.) s)               "+
                "))                                         ";

IFn fn = (IFn)RT.var("clojure.core", "eval").invoke(RT.var("clojure.core","read-string").invoke(script));

fn.invoke("hello");

更新:
下面的示例代码工作正常:

package hello_clj;

import clojure.lang.RT;
import clojure.lang.IFn;

public class Main {

    public String passBackMsg(String s) {
        return s;
    }

    public static void main(String[] args) {
        String script = "(do (import 'hello_clj.Main) (fn [s] " + 
                        "(.passBackMsg (Main.) s) ))";

        IFn fn = (IFn)RT.var("clojure.core", "eval").invoke(RT.var("clojure.core","read-string").invoke(script));
        System.out.print(fn.invoke("Hello"));
    }

}

转载注明原文:Java – > Clojure – > Java - 代码日志