1

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?

1 Answer 1

4

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Worked. The recipe is "snip the repo name off the front and replace all slashes with dots." My co-worker next door has also taught me that this is the notion of a Java "package" and showed me a small example. Lights are coming on.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.