Reb.Cabin
Reb.Cabin

Reputation: 5567

Importing Java classes into Clojure from local repo?

I checked possible duplicates for this question, and I didn't find one that answers my problem. Most of them stop at naming the .jar file or the maven repo. I need help on looking inside a local repo and its jar to import classes. The SO answers I found that address import don't address local repos.

Consider the following project.clj, noting the two lines I added to a fresh leiningen project I created via lein app sc-tester:

(defproject sc-tester "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"}
  :dependencies [[org.clojure/clojure "1.8.0"]
                 [local/scxml "2.2.0"]]       ;;; <<<---=== local jar reference
  :main ^:skip-aot sc-tester.core
  :target-path "target/%s"
  :repositories [["local" "file:local-repo"]] ;;; <<<---=== local repo reference
  :profiles {:uberjar {:aot :all}})

I created the local jar reference with the following command:

lein deploy local local/scxml 2.2.0 ~/Documents/commons-scxml/target/commons-scxml2-2.0-SNAPSHOT.jar

That command resulted in the following contents of local_repo:

local-repo/
`-- local
    `-- scxml
        |-- 2.2.0
        |   |-- scxml-2.2.0.jar
        |   |-- scxml-2.2.0.jar.md5
        |   `-- scxml-2.2.0.jar.sha1
        |-- maven-metadata.xml
        |-- maven-metadata.xml.md5
        `-- maven-metadata.xml.sha1

A call of lein deps does not fail (but that's not the same as succeeding!):

lein deps :tree
[clojure-complete "0.2.4" :exclusions [[org.clojure/clojure]]]
[local/scxml "2.2.0"]
[org.clojure/clojure "1.8.0"]
[org.clojure/tools.nrepl "0.2.12" :exclusions [[org.clojure/clojure]]]

The jar file contains a bunch of classes; here is an excerpt with a few for context, including a couple, SCXML and SCXMLExecutor, I'd like to import:

$ jar tvf local-repo/local/scxml/2.2.0/scxml-2.2.0.jar 
...
 2275 Mon ... 2016 org/apache/commons/scxml2/model/Script.class 
 5857 Mon ... 2016 org/apache/commons/scxml2/model/SCXML.class
 8963 Mon ... 2016 org/apache/commons/scxml2/model/Send.class
... 
12466 Mon ... 2016 org/apache/commons/scxml2/SCXMLExecutionContext.class
11358 Mon ... 2016 org/apache/commons/scxml2/SCXMLExecutor.class
  848 Mon ... 2016 org/apache/commons/scxml2/SCXMLExpressionException.class
...

Now I fire up a repl and start guessing how to name those classes in a call of import:

$ lein repl
nREPL server started on port 60765 on host 127.0.0.1 - nrepl://127.0.0.1:60765
REPL-y 0.3.7, nREPL 0.2.12
Clojure 1.8.0
Java HotSpot(TM) 64-Bit Server VM 1.8.0_101-b13
...

sc-tester.core=> (import 'local/scxml.SCXML)
ClassNotFoundException scxml.SCXML  java.net.URLClassLoader.findClass 
(URLClassLoader.java:381)
sc-tester.core=> (import 'local/scxml/org/apache/commons/scxml2/model/SCXML)
ClassNotFoundException scxml/org/apache/commons/scxml2/model/SCXML 
java.lang.Class.forName0 (Class.java:-2)

Hmmm. A different kind of error, but still no help in figuring out the right answer. Let's try a dot in a random place instead of a slash:

sc-tester.core=> (import 'local/scxml.org/apache/commons/scxml2/model/SCXML)
ClassNotFoundException scxml.org/apache/commons/scxml2/model/SCXML
java.lang.Class.forName0 (Class.java:-2)

Let's try almost-all-dots:

sc-tester.core=> (import 'local/scxml.org.apache.commons.scxml2.model.SCXML)
ClassNotFoundException scxml.org.apache.commons.scxml2.model.SCXML
java.net.URLClassLoader.findClass (URLClassLoader.java:381)

Let's try snipping off the name of the repo:

sc-tester.core=> (import 'org/apache/commons/scxml2/model/SCXML)
ClassNotFoundException apache/commons/scxml2/model/SCXML  
java.lang.Class.forName0 (Class.java:-2)

etc. etc. etc. (tried many permutations and guesses).

Questions:

  1. Did I set up the local repo correctly, in other words, is it even possible to name the classes correctly in a call of import with my set-up?

  2. If so, how can I import the java classes into Clojure? What's the right syntax for naming these beasts?

Upvotes: 1

Views: 422

Answers (1)

Joost Diepenmaat
Joost Diepenmaat

Reputation: 17761

You should be able to import classes from any jar on your classpath using just the classname and package:

(import 'org.apache.commons.scxml2.model.SCXML)

If that doesn't work, the jar is not on your classpath and you should fix that first.

Upvotes: 4

Related Questions