Sandro Padin

Using a Local Jar in Your Clojure Project

I recently wrote a simple Java web server named Jerver as a task during my apprenticeship. After completing the server, my next task was to use that server in Clojure and integrate it with Ticlj, my Clojure-based Tic Tac Toe game. I was to package the Java server as a .jar that I would somehow use in my new project.

I’d previously used libraries like Speclj and Joodo which have stable and documented APIs. My Java server was neither stable nor documented, so I needed a way to quickly and reliably update the server jar when I realized and implemented new APIs I needed to expose to my Clojure project.

I noticed up front this needed to be some sort of shell script which runs the series of Maven commands for importing the jar from my server project.

I came up with the following shell script:

    mkdir -p lib/local
 
    # Set some defaults for JAR_VERSION, JAR_SOURCE and ARTIFACT_ID below.
    JAR_VERSION=${JAR_VERSION:=0.0.1-SNAPSHOT}
    JAR_SOURCE=${JAR_SOURCE:=/Users/sandropadin/IdeaProjects/Jerver/target/jerver.jar}
    ARTIFACT_ID=${ARTIFACT_ID:=jerver}
     
    mvn deploy:deploy-file -DgroupId=local \
                           -DartifactId=$ARTIFACT_ID \
                           -Dversion=$JAR_VERSION \
                           -Dpackaging=jar \
                           -Dfile=$JAR_SOURCE \
                           -Durl=file:lib
     
     mvn -U dependency:resolve

I saved this file at script/import-jar made it executable (chmod +x) then I called it like so:

     $ script/import-jar

I would then just run this command multiple times during my development process to quickly update the jar my Clojure project was using.

The Clojure project.clj imports the jar:

    :dependencies [[org.clojure/clojure "1.5.1"]
                   [local/jerver "0.0.1-SNAPSHOT"]] 

Then my code uses the classes within the jar:

    (ns ticlj-on-jerver.api.resolver
      (:use [ticlj-on-jerver.api.response :only [set-status-code
                                                 add-header]]))

    (defrecord Resolver [callback]
      ; This is an interface defined in the Java server
      com.jerver.http.route.Routable
      (resolve [this request response]
        (let [callback (:callback this)]
          (callback request response))))

    (defn resolver [callback]
      (Resolver. callback))

After all the setup, once I made a change to the Java server project, I would generate the package using Maven, then run my import-jar script to import the newly generated package and update the dependencies in my Clojure project.