13
votes

How can I take a large existing Java project and start to add Clojure modules? For example, in the code below, I'd like to make the following functions available in Java: state?, zip?, state-list, zipcode-list. The two predicates will return a boolean, but the "getters" will return arrays.

(def *states* (list "NJ" "NY" "CA"))
(def *zipcodes*  (list 12345 54343 98765))

(defn member [x sq]
  (if (seq sq)
    (if (= x (first sq))
      sq
      (recur x (rest sq)))))

(defn state? [aState]
  (not (= (member aState *states*) nil)))

(defn zip? [aZip]
  (not (= (member aZip *zipcodes*) nil)))

(defn state-list []
  *states*)

(defn zipcode-list []
  *zipcodes*)
;; ---------------
(state? "AA")
(state? "CA")
(zip? 11111)
(zip? 12345)
3

3 Answers

11
votes

I would compile it using leiningen then add the jar file to my java project as a build dep. Here is a great video on using leiningen. then you would call it directly from java. Leiningen has an uberjar option that bulds in clojure and all your clojure dependencies so you only have to worry about one file. I like this because its less work.

A more java friendly approach would be to add an ant task to build it along with the java project its just a little more work

for the functions that need to return proper java arrays call to-array on them

contrary to many of the top "calling clojure from java" hits you should not need to call the clojure runtime RT.

PS: my favorite tag line "I would like to use a java library called clojure" I asked Rich he said this was cool ;)

2
votes

It is easier to take an existing Java application and wrap it in Clojure than the other way around, because Java interop from Clojure is very simple.

As you are asking how to access Clojure from Java, the answer is that you either need to bootstrap load Clojure code, or you need to generate Java class files that can be used from your Java project. Bootstrapping involves linking to the clojure jar and accessing the load function to load clojure source. To generate Java classes look into AOT (see example on the website).

2
votes

My recommended approach is the following:

  • Continue to manage the Java project with whatever you main build tool is (presumably Maven?)
  • Add Clojure as a dependency. It will work just like any other library .jar file
  • Call into the Clojure code from Java. A typical use case would be to require a namespace to do this, grab a reference to whatever IFn you want to call and call the function via IFn.invoke

I recommend this approach because it is generally simpler to add Clojure to a Java project instead of the other way round: this is especially true if you have other developers to consider or are using tools that assume a regular Java project. It's also less scary to managers: all you are doing is using an extra little Java library :-)

I made a small utility library that does a lot of the work required for calling into Clojure from Java that you may find useful: