Java -> Clojure -> Java
clojure, java
Solution
Try this:
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");
UPDATED: Below sample code works fine:
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"));
}
}
Problem
I am trying to use Clojure as a scripting language from a host Java program. The idea being that the end user will be able to write Clojure scripting code that will call a domain-specific Java API. At runtime, the host Java program will evaluate the end-user's Clojure script (which will in turn call the domain APIs). So I started with a dead-simple prototype to explore the terrain. domain ``` package a.problem.domain; public class Domain { public Domain() { } public String defaultMsg() { return "default"; } public String passBackMsg(String s) { return s; } } ``` Host Java program (end user's Clojure script hard-coded for simplicity) ``` 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))); ``` (code snippet taken from here) So far so good. However I couldn't find a way to invoke the second method (the one that requires an argument). Instead I resorted to dynamically generating the Clojure script at runtime and replacing a placeholder with a literal that represents the result of calling the domain method passBackMsg. Obviously, this is unsatisfactory and doesn't go very far (what if I want to pass a java.sql.Connection to my Clojure script ?). So, how do I invoke the passBackMsg method from the host Java program? When I try the following: ``` 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 ``` I get: ``` java.lang.IllegalStateException: Can't change/establish root binding of: *ns* with set ``` ... on line-A. When I try without the ns and with: ``` RT.var("user", "numberToString").invoke(33) ``` ("user" being a wild guess as I don't see a var method without a namespace argument) I get an: ``` java.lang.IllegalStateException: Attempting to call unbound fn: #'user/numberToString" ``` ... on line-B.