How to add a Java instance as context when using clojure as a scripting language?

96 views Asked by At

I found the amazing question How can I use clojure as scripting language for a Java program? which helped tremendously, but I can't figure out how to get an existing Java instance into Clojure. The use case is something really similar to AutoCad's AutoLisp. I want to let users manipulate an application with scripting so that they are free to do more without my help or input. I want to have a class that does some work

public class Testing {
    public void work() {
        // ....
    }
}

and then add it to Clojure

public class Main {
    public static void main() {
        Testing t = new Testing()
        IFn eval = Clojure.var("clojure.core", "eval");
        System.out.println(eval.invoke(Clojure.read("(import Testing)")));
        // How do i get "t" into clojure?
        System.out.println(eval.invoke(Clojure.read("(.work t)")));
    }
}

However I can't figure out how. I don't seem to be able to invoke def with arguments from java. I have been fiddling with this and with documentation for a while and can't seem to figure it out.

1

There are 1 answers

5
Eugene Pakhomov On BEST ANSWER
import clojure.java.api.Clojure;
import clojure.lang.Var;
import clojure.lang.RT;
import clojure.lang.Compiler;


public class Main {
    public static void main(String[] _argv) {
        // Using String instead of Testing just to avoid having to
        // deal with multiple files during compilation.
        String s = "Hello there";

        // Needed to allow creating new namespaces.
        // If you ever get stuck with some functionality not working, check out
        // Compiler.load - there are other bindings in there which, I guess, might be important.
        // So you can either copy all the bindings here or simply use Compiler.load instead of
        // Compiler.eval for script pieces that don't require bindRoot.
        Var.pushThreadBindings(RT.mapUniqueKeys(RT.CURRENT_NS, RT.CURRENT_NS.deref()));
        try {
            Compiler.eval(Clojure.read("(ns user)"));
            // def returns the var itself.
            ((Var) Compiler.eval(Clojure.read("(def s)"))).bindRoot(s);

            Compiler.eval(Clojure.read("(println s \"in\" (ns-name *ns*)))"));
        } finally {
            Var.popThreadBindings();
        }
    }
}