BetterThanTomorrow / calva

Clojure & ClojureScript Interactive Programming for VS Code
https://marketplace.visualstudio.com/items?itemName=betterthantomorrow.calva
Other
1.68k stars 217 forks source link

java.lang.NoClassDefFoundError: com/fasterxml/jackson/core/StreamWriteFeature #747

Closed PratDesai closed 3 years ago

PratDesai commented 4 years ago

I am trying to get a basic crux-sql example running on a Windows 10 machine using Leiningen. Using @jonpither example code https://github.com/jonpither/crux-sql-demo.

Machine details: Windows 10 pro v1909 openjdk version "13.0.2" 2020-01-14

When I execute the test-issue function using lein repl in a Powershell window it works fine with the following output:

#{["Ivan"] ["Dmitry"] ["Yuri"] ["Antonina"] ["Slata"] ["Denis"]
  ["Sergei"] ["Maria"]}
({:name "Antonina"}
 {:name "Slata"}
 {:name "Maria"}
 {:name "Sergei"}
 {:name "Slata"})
nil

However, executing the same function via Calva repl in VS Code I get the following error:

ERROR: Unhandled REPL handler exception processing message {:op stacktrace, :id 50, :session cacc6b3a-636c-4ea3-a44f-22e79d8aadb8}
java.lang.NoClassDefFoundError: com/fasterxml/jackson/core/StreamWriteFeature
        at java.base/java.lang.Class.getDeclaredMethods0(Native Method)
        at java.base/java.lang.Class.privateGetDeclaredMethods(Class.java:3167)
        at java.base/java.lang.Class.getDeclaredMethods(Class.java:2310)
        at clojure.reflect$declared_methods.invokeStatic(java.clj:152)
        at clojure.reflect.JavaReflector.do_reflect(java.clj:183)
        at clojure.reflect$fn__11882$G__11878__11885.invoke(reflect.clj:44)
        at clojure.reflect$fn__11882$G__11877__11889.invoke(reflect.clj:44)
        at clojure.core$partial$fn__5839.invoke(core.clj:2624)
        at clojure.reflect$type_reflect.invokeStatic(reflect.clj:100)
        at clojure.reflect$type_reflect.doInvoke(reflect.clj:58)
        at clojure.lang.RestFn.applyTo(RestFn.java:139)
        at clojure.core$apply.invokeStatic(core.clj:667)
        at clojure.reflect$reflect.invokeStatic(reflect.clj:121)
        at clojure.reflect$reflect.doInvoke(reflect.clj:115)
        at clojure.lang.RestFn.invoke(RestFn.java:439)
        at cider.nrepl.inlined_deps.orchard.v0v5v5.orchard.java$class_info_STAR_.invokeStatic(java.clj:195)

        ...  more lines
(defproject my-crux-sql "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0"
            :url "https://www.eclipse.org/legal/epl-2.0/"}
  :dependencies [[org.clojure/clojure "1.10.1"]
                 [juxt/crux-sql "RELEASE"]
                 [juxt/crux-rocksdb "RELEASE"]]
  :main ^:skip-aot my-crux-sql.core
  :target-path "target/%s"
  :profiles {:uberjar {:aot :all
                       :jvm-opts ["-Dclojure.compiler.direct-linking=true"]}})
(ns my-crux-sql.core
  (:require [crux.api :as crux]
            [clojure.java.io :as io]
            [clojure.pprint]
            crux.calcite)
  (:gen-class))

(defn uuid-gen []
  (java.util.UUID/randomUUID))

(defn start-rocks-node [storage-dir]
  (crux/start-node {:crux.node/topology '[crux.standalone/topology
                                          crux.kv.rocksdb/kv-store
                                          crux.calcite/module]
                    :crux.standalone/event-log-dir (io/file storage-dir "event-log")
                    :crux.standalone/event-log-kv-store 'crux.kv.rocksdb/kv
                    :crux.kv/db-dir (str (io/file storage-dir "indexes"))}))

(defn random-person []
  {:crux.db/id (uuid-gen)
   :name       (rand-nth ["Ivan" "Slata" "Sergei" "Antonina" "Yuri" "Dmitry" "Maria" "Denis"])
   :last-name  (rand-nth ["Ivanov" "Petrov" "Sidorov" "Kovalev" "Kuznetsov" "Voronoi"])
   :sex        (rand-nth [:male :female])
   :age        (rand-int 100)
   :salary     (rand-int 100000)})

(defn query [node q]
  (with-open [conn (crux.calcite/jdbc-connection node)]
    (let [stmt (.createStatement conn)]
      (->> q (.executeQuery stmt) resultset-seq))))

(defn test-issue []
  (let [node (start-rocks-node "db")]
    (doseq [p (take 100 (repeatedly random-person))]
      (let [tx (crux/submit-tx node [[:crux.tx/put p]])]
        (crux/await-tx node tx)))
    (clojure.pprint/pprint (crux/q (crux/db node) {:find  '[name]
                                                   :where ['[e :name name]]}))
    (crux/submit-tx node [[:crux.tx/put {:crux.db/id             :crux.sql.schema/person
                                         :crux.sql.table/name    "person"
                                         :crux.sql.table/query   '{:find  [?id ?name]
                                                                   :where [[?id :name ?name]]}
                                         :crux.sql.table/columns '{?id :keyword, ?name :varchar}}]])
    (crux/entity (crux/db node) :crux.sql.schema/person)
    (clojure.pprint/pprint (take 5 (query node "SELECT PERSON.NAME FROM PERSON")))
    (.close node)))

(comment
  (test-issue))
bpringe commented 4 years ago

I pulled down the linked repo (the tool.deps project vs your leiningen), and added your code above. I ran Calva jack-in, eval'd the file containing your code, and ran test-issue and I get the output you showed you got from lein repl.

I then used your project.clj and ran jack-in with Calva, choosing Leiningen, and got the error you get.

I ran it with lein repl and it succeeded, like you say.

I then wondered if anything being injected by our jack-in could be causing this somehow and I realized if you remove the clj-kondo dependency injection from the jack-in command, it works. This is the altered command for my machine (linux), that the code works with:

lein update-in :dependencies conj '[nrepl"0.6.0"]' -- update-in :plugins conj '[cider/cider-nrepl"0.23.0"]' -- update-in '[:repl-options :nrepl-middleware]' conj '["cider.nrepl/cider-middleware"]' -- repl

I'm unsure what's going on, but for now you can either run it with jack in using clojure cli (deps.edn) instead of leiningen (project.clj), or you can run jack-in for leiningen, copy the command it issues in the jack-in terminal, and remove the part that uses update-in to inject clj-kondo. (The quote escaping is different for Windows.)

clj-kondo is currently used as a dependency to find var usages for adding decorations to show instrumented forms for the debugger, so this is the only thing you'd be lacking if you did that. This is separate from the extension that lints, so you would still have linting.

@PEZ Maybe we do need a different way of using clj-kondo, like @borkdude was saying. Though I have no idea what's going on here, as it works with tools.deps.

borkdude commented 4 years ago

Tools.deps and leiningen have different strategies for resolving dependencies. Tools.deps basically chooses newer over older in case of conflict, and lein/maven basically chooses first over later. To debug this you could try to look at the output of lein deps :tree and clojure -Stree.

borkdude commented 4 years ago

My guess would be that clj-kondo depends on transit-java (indirectly via transit-clj) and this has jackson.core version 2.8.7:

https://github.com/cognitect/transit-java/blob/cff7111c2081fc8415cd9bd6c6b2ba518680d660/pom.xml#L40

The class that's not being found was introduced in version 2.10.0: https://github.com/FasterXML/jackson-core/issues/571

So maybe a direct dependency on this newer version of jackson.core in your project.clj would help solve this issue, as a workaround.

PratDesai commented 4 years ago

Thank you both for a prompt response which such insightful comments.

@bpringe, I'll try out the command string that you posted. @borkdude, I'll try clj on Windows and see if that works with Calva jack-in as is.

borkdude commented 4 years ago

@PratDesai If clj on Windows gives you trouble (e.g. because of Powershell, cmd.exe), you can also try deps.exe from here:

https://github.com/borkdude/deps.clj

bpringe commented 3 years ago

Closing this issue since it's not really Calva related, but rather a dependency resolution issue.