For a recent project, I wanted to verify the correctness of a distributed queue implementation based on Amazon SQS. For this, I turned to the Jepsen library for verifying distributed systems. Jepsen is written in Clojure and the first task was to get Jepsen to compile with a Java library hosted on our internal Maven repository. I googled for a while, asked around, and assembled instructions from a few different places. Here then, is a single blog post summarizing the solution for future use.

The key to getting this to work is to add a few directives to your Leiningen project configuration. Particularly,

Add your private repository to the :repository directive

Leiningen needs to know the location of any private Maven repositories that host your source code. This is done through the :repository directive.

;; These repositories will be searched for :dependencies and
;; :plugins and will also be available to deploy to.

:repositories [["your-private-maven-repository" {:url "http://..."}]]

If you require authorization for your repository, you can add your credentials to your leiningen profile. Within the :auth section, you do not need to specify http:// before the repository URL.

$ cat ~/.lein/profiles.clj
{:auth {:repository-auth {#"your-private-maven-repository-endpoint"
                           {:username "<your username>"
                            :password "<your password>"}}}}

Add Java library dependencies

Java library dependencies are added exactly the same as Clojure dependencies. However you must explicitly list the groupId and artifactId for Maven hosted artifacts:

:dependencies [[org.clojure/clojure "1.8.0"]
               [org.apache.thrift/libthrift "0.9.3"]
               [jepsen "0.1.4"]])

Add Java code called by Clojure

Java code called by Clojure must be compiled and made available to the Clojure compiler. Leiningen does this for us through the :java-source-paths directive. Specify any Java code here:

;;; Filesystem Paths
;; If you'd rather use a different directory structure, you can set these.
;; Paths that contain "inputs" are string vectors, "outputs" are strings.

:java-source-paths ["src/main/java"]  ; Java source is stored separately.

A Minimal Sample Configuration

Putting this all together, the following project configuration is used to add Java library code from a private Maven repository and local Java source code to a Leiningen project:

(defproject my-project "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :main jepsen.my-project
  :repositories [["my-private-maven-repository" {:url "http://my-private-maven-endpoint"}]]
  :java-source-paths ["src/main/java"]
  :dependencies [[org.clojure/clojure "1.8.0"]
                 [<my-private-group-id>/<my-private-artifact-id> "2.4.0"]
                 [jepsen "0.1.4"]])