Welcome! Please see the About page for a little more info on how this works.

0 votes
in REPL by

Hi!
I am develop a idea plugin with clojure+nrepl.
The project gradle dependencies :

dependencies {
    implementation("org.clojure:clojure:1.10.0")
    implementation("nrepl:nrepl:1.0.0")
}

I get FileNotFoundException when I invoke :

RT.var("clojure.core", varName)

Where is the mistake?
Thanks!

1 Answer

+1 vote
by
selected by
 
Best answer

RT is an internal implementation class.

The Java API for Clojure is https://clojure.github.io/clojure/javadoc/clojure/java/api/package-summary.html.

by
Thanks for your help.
I have been read the Java API for Clojure. And It throw a same Exception when I invoke
Clojure.var("clojure.core", "+");
I resolved the problem by
Thread.currentThread().setContextClassLoader()
maybe idea plugin's environment is special.
Thanks again
by
Hi, alexmiller.
how can I create a nrepl client use Java API for Clojure?
I can't translate Clojure to Java such as:

=> (require '[nrepl.core :as nrepl])
nil
=> (with-open [conn (nrepl/connect :port 59258)]
     (-> (nrepl/client conn 1000)
         (nrepl/message {:op "eval" :code "(time (reduce + (range 1e6)))"})
         doall      ;; `message` and `client-session` all return lazy seqs
         pprint))
by
For any Clojure var, you will use Clojure.var() to get a reference to it, then invoke() on it. For literals like the message, you can use either Clojure.read() to read Clojure data from a string, or use constructor functions like hash-map. with-open is a macro but in this case, it's basically replicating what you can do with try-with-resources in Java so you don't really need it. -> will need to be unrolled here or you could put more of this into a Clojure function and just invoke it.

I haven't compiled this but you'll end up with something like:

```

private static final IFn require = Clojure.var("clojure.core", "require");
private static final IFn doall = Clojure.var("clojure.core", "doall");

private static final Object portKW = Clojure.read(":port");
private static final Object opKW = Clojure.read(":op");
private static final Object codeKW = Clojure.read(":code");

private static final IFn connect;
private static final IFn client;
private static final IFn message;

static {
  require.invoke(Clojure.read("nrepl.core"));
  connect = Clojure.var("nrepl.core", "connect");
  client = Clojure.var("nrepl.core", "client");
  message = Clojure.var("nrepl.core", "message");
}

public Object getConnection(int port) {
   return connect.invoke(portKW, port);
}

public Object getClient(Object conn, int timeout) {
  return client.invoke(conn, timeout);
}

public Object send(Object client, Object message) {
  Object result = message.invoke(client, message);
  return doall.invoke(result);
}
```

then


```
try (Object conn = getConnection(59258)) {
  Object client = getClient(conn, 1000);
  Object result = send(client, Map.of(opKW, "eval", codeKW, "(time (reduce + (range 1e6)))"));
  // result here is a map, do what you want with it
}
```
by
edited by
Thanks, it connected sucecessfully,  There is a small modification:

public static IPersistentMap evalCodeMap() {
        Map<Object, Object> map = Maps.newHashMap();
        map.put(Clojure.read(":op"), Clojure.read("eval"));
        map.put(Clojure.read(":code"), Clojure.var("clojure.core", "eval").invoke("(+ 1 2)"));
        return PersistentHashMap.create(map);
    }

Clojure.var("nrepl.core", "message").invoke(client , evalCodeMap())

BTW, It seems that Clojure code is more simple.
it better to code with Clojure then call Clojure from Java? How to do that? gen-class or require namespace?
...