3

I have Clojure function generate-id.

Source code:

(ns url62.core)
...
(defn generate-id []
  (int-to-base62 (java.math.BigInteger. (clojure.string/replace (str (java.util.UUID/randomUUID)) "-" "") 16)))

I need to execute this function from Java.

I have try with code like this:

IFn generateId = Clojure.var("url62.core", "generate-id");
generateId.invoke(UUID.randomUUID());

But this doesn't work:

java.lang.IllegalStateException: Attempting to call unbound fn: #'url62.core/generate-id

    at clojure.lang.Var$Unbound.throwArity(Var.java:43)
    at clojure.lang.AFn.invoke(AFn.java:32)
    at clojure.lang.Var.invoke(Var.java:379)
MariuszS
  • 30,646
  • 12
  • 114
  • 155
  • 1
    Take a look at https://stackoverflow.com/a/23555959/597473 – Piotrek Bzdyl Sep 26 '17 at 22:29
  • On the one hand, I agree that this question is a duplicate of that one. But I don't really want to close it as a duplicate, since as @PiotrekBzdyl says, the best answer to that question is not the accepted answer but one added later. Alan Thompson has a good answer to this question as well, saying much the same thing as the linked answer from Alex Miller. – amalloy Sep 26 '17 at 23:33
  • Updated question -> https://stackoverflow.com/questions/46441626/mixed-clojure-and-java-project-in-maven – MariuszS Sep 27 '17 at 07:20

1 Answers1

6

You forgot to require the Clojure namespace:

Here is the project structure:

-rwxrwxr-x 1 alan alan  162 Sep 26 15:27 compile-run-java.bash*
-rwxrwxr-x 1 alan alan  439 Oct 19  2016 project.clj*
-rw-rw-r-- 1 alan alan  142 Sep 26 16:38 src/embedded_clojure/core.clj
-rw-rw-r-- 1 alan alan  586 Sep 26 15:21 src-java/mypkg/Main.java
-rw-rw-r-- 1 alan alan  125 Oct 19  2016 test/tst/embedded_clojure/core.clj

and the project.clj file:

(defproject embedded-clojure "0.1.0-SNAPSHOT"
  :dependencies [
    [org.clojure/clojure "1.8.0"]
  ]
  :java-source-paths ["src-java"]
  :main embedded-clojure.core
  :target-path "target/%s"
  :profiles {:uberjar {:aot :all}})

Here is the Java class that calls the embedded Clojure function:

package mypkg;
import clojure.java.api.Clojure;
import clojure.lang.IFn;
class Main {
  public static void main( String[] args ) {
    System.out.println( "Java Main.main()" );

    // clojure.core is automatically "required"; you don't need to
    IFn plus = Clojure.var("clojure.core", "+");
    System.out.println( "  plus: " + plus.invoke(1, 2) );

    // any other namespace needs to be "required"
    IFn require = Clojure.var("clojure.core", "require");
    require.invoke(Clojure.read("embedded-clojure.core"));

    IFn add  = Clojure.var("embedded-clojure.core", "add");
    System.out.println( "  add:  " +  add.invoke(2, 3) );
  }
}

Clojure file:

(ns embedded-clojure.core
  (:gen-class))

(defn add [x y] (+ x y))

(defn -main [& args]
  (println "Clojure -main:  (add 4 5) =>" (add 4 5)))

Clojure test file:

(ns tst.embedded-clojure.core
  (:use embedded-clojure.core
        clojure.test))

(deftest simple-add
  (is (= 13 (add 6 7))))

Run Script compile-run-java.bash

#!/bin/bash  -v

lein clean
lein uberjar
# Use Java main()
java -cp /home/alan/demo/embedded-clojure/target/uberjar/embedded-clojure-0.1.0-SNAPSHOT-standalone.jar \
  mypkg.Main

# Use Clojure -main
java -cp /home/alan/demo/embedded-clojure/target/uberjar/embedded-clojure-0.1.0-SNAPSHOT-standalone.jar \
  embedded_clojure/core

and now we can run from the command line:

 > ./compile-run-java.bash
#!/bin/bash  -v

lein clean
lein uberjar
Compiling 1 source files to /home/alan/demo/embedded-clojure/target/uberjar/classes
Compiling embedded-clojure.core
Created /home/alan/demo/embedded-clojure/target/uberjar/embedded-clojure-0.1.0-SNAPSHOT.jar
Created /home/alan/demo/embedded-clojure/target/uberjar/embedded-clojure-0.1.0-SNAPSHOT-standalone.jar
# Use Java main()
java -cp /home/alan/demo/embedded-clojure/target/uberjar/embedded-clojure-0.1.0-SNAPSHOT-standalone.jar \
  mypkg.Main
Java Main.main()
  plus: 3
  add:  5

# Use Clojure -main
java -cp /home/alan/demo/embedded-clojure/target/uberjar/embedded-clojure-0.1.0-SNAPSHOT-standalone.jar \
  embedded_clojure/core
Clojure -main:  (add 4 5) => 9

We can also use lein to run the Clojure -main or the Clojure tests:

> lein test
lein test tst.embedded-clojure.core
Ran 1 tests containing 1 assertions.
0 failures, 0 errors.

> lein run
Clojure -main:  (add 4 5) => 9
Alan Thompson
  • 29,276
  • 6
  • 41
  • 48
  • Thanks, I forget about maven part ;) I have clojoure source mixed with java code (separate directories) in one project package as jar. – MariuszS Sep 27 '17 at 07:02
  • I have moved my question to new question: https://stackoverflow.com/questions/46441626/mixed-clojure-and-java-project-in-maven – MariuszS Sep 27 '17 at 07:20