Search code examples
clojurejvmleiningen

Could not locate clojure/data/json: How do I get my REPL to see this (and similar) dependencies


I am using lein repl without a project so there is no project.clj.

I am running Leiningen 2.8.1 on Java 1.8.0_191 OpenJDK 64-Bit Server VM.

When I require a Clojure dependency that I assume should just work - like clojure.data.json - I notice that it is not in my .m2 directory. Is that why I am getting a FileNotFoundException Could not locate clojure/data/json__init.class or clojure/data/js on.clj on classpath? I can't find my other Clojure dependencies there either so I don't know where they reside and if this dependancy should be in .m2 or not.

I understand the error message but without knowing its location or even knowing how to properly add it to the CLASSPATH for the REPL to see it, I remain stuck.

Is this a dependency that I still need to install? If so, how do I install it without going through a project?

I don't understand the JVM as I am new to it, so add a little extra information in your answer.


I have looked at this, this, this, this and this. I don't know if I am overlooking anything so your help will really be appreciated.


Solution

  • I am using lein run without a project so there is no project.clj.

    If you're using Leiningen, this'll be much easier if you create a project.clj file that declares your dependencies. Leiningen will read project.clj and handle fetching any missing dependencies to your local Maven repository, and add them to your classpath when you start your REPL/application. (lein run doesn't work for me in a directory without a project.clj; I get an error: No :main namespace specified in project.clj.. Did you mean lein repl?)

    When I require a Clojure dependency that I assume should just work - like clojure.data.json - I notice that it is not in my .m2 directory.

    clojure.data.json doesn't ship with Clojure — it's a separate dependency that must be fetched and added to your classpath in order to use it. The classpath tells the JVM where to look when it loads class files. Leiningen will do both of these things for you if you declare the dependency in project.clj:

    :dependencies [[org.clojure/clojure "1.10.0"]
                   [org.clojure/data.json "0.2.6"]]
    

    You can also use the lein deps command if you only want to fetch dependencies.

    You can create a new/blank Leiningen project with lein new project_name_goes_here. It will have a project.clj with a few boilerplate entries and a :dependencies key where you can declare dependencies.

    I understand the error message but without knowing its location or even knowing how to properly add it to the CLASSPATH for the REPL to see it, I remain stuck. Is this a dependency that I still need to install? If so, how do I install it without going through a project?

    You could manually download it from the internet, then manually add its path to your classpath, but if you're already using Leiningen it's much easier to add a line to a project.clj file and have Leiningen handle this for you.

    If using a project.clj file w/Leiningen isn't an option, there are other ways to use Clojure and resolve dependencies/build a classpath at runtime. Boot accommodates this workflow, you can use Leiningen like this with a little added effort, as well as the newer tools.deps tooling. There are examples of each in this ClojureVerse thread, but note that some of these approaches are doing essentially the same thing as declaring the dependency in a file — instead declaring them as CLI arguments.

    For example, using Clojure CLI tooling:

    $ clj -Sdeps "{:deps {org.clojure/data.json {:mvn/version \"0.2.6\"}}}"
    Clojure 1.9.0
    user=> (require '[clojure.data.json :as json])
    nil
    user=> (json/write-str {:foo "bar"})
    "{\"foo\":\"bar\"}"
    user=> (System/getProperty "java.class.path")
    "src:
    /Users/me/.m2/repository/org/clojure/clojure/1.9.0/clojure-1.9.0.jar:
    /Users/me/.m2/repository/org/clojure/data.json/0.2.6/data.json-0.2.6.jar:
    /Users/me/.m2/repository/org/clojure/spec.alpha/0.1.143/spec.alpha-0.1.143.jar:
    /Users/me/.m2/repository/org/clojure/core.specs.alpha/0.1.24/core.specs.alpha-0.1.24.jar"
    

    You could create a deps.edn file containing {:deps {org.clojure/data.json {:mvn/version \"0.2.6\"}}} in the same directory, and clj would read that, resolve the dependencies if necessary, and build the classpath accordingly.