Hello! I'm trying to build an uberjar of my app using depstar and I get this error...
Exception in thread "main" Syntax error compiling at (calculators/web.clj:1:1).
...
Caused by: java.lang.ClassNotFoundException: org.eclipse.jetty.server.handler.gzip.GzipHandler
The calculators.web namespace has this...
(:import org.eclipse.jetty.server.handler.gzip.GzipHandler)
I'm using ring-jetty-server 1.9.2, which includes jetty-server 9.4.38.v20210224 , where the GzipHandler
class is defined. Moreover, when I start the app from the REPL, there are no issues, the GzipHandler
class is found and I get gzipped responses from the server.
Any idea on why depstar doesn't find the class?@xavi when you run your app from the REPL do you add any aliases that cause Ring to be added?
No. I have Ring directly in :deps...
{:deps
{ring/ring-core {:mvn/version "1.9.2"}
ring/ring-jetty-adapter {:mvn/version "1.9.2"}
...}
}
OTOH, I tried removing the references to GzipHandler and now it doesn't find Stuart Sierra's Component, which the app also depends on.It seems it doesn't find any dependency?
I tried changing the :replace-deps
in the depstar alias with :extra-deps
(I know that according to the depstar README I have to use :replace-deps
, but I'm exploring the problem š , then it fails with...
Execution error (NullPointerException) at hf.depstar.uberjar/compile-arguments (uberjar.clj:545).
Cannot invoke "clojure.lang.Named.getName()" because "x" is null
Also, I had a dev/user.clj
and I had "dev" in paths...
:paths ["dev" "resources" "src/clj" "src/cljs" "src/cljc"]
I removed "dev" from paths and now...
clojure -X:uberjar :jar app.jar
returns...
Execution error (NullPointerException) at hf.depstar.uberjar/compile-arguments (uberjar.clj:545).
Cannot invoke "clojure.lang.Named.getName()" because "x" is null
(So the same error I got after changing :replace-deps
with :extra-deps
)ah, just before that "Execution error...", there's...
[main] INFO hf.depstar.uberjar - Compiling nil ...
Oops, sorry... I wasn't specifying the namespace to compile. It worked after specifying :main-class
clojure -X:uberjar :aot true :jar app.jar :main-class calculators.main
...and that works even after adding back the GzipHandler
, but not if I also add back "dev" to :paths
Ok, no problem, I don't need dev/user.clj in the uberjar, but I still wonder why that breaks it
Well, if something is dev-only, it should not be on your paths/deps by default ā you should put it behind an alias.
right... just wondering why that breaks the uberjar build
Iām curious too. I donāt know if you can share your deps.edn
file and the contents of your dev
folder?
/dev
only has user.clj
...
; <https://github.com/jasongilman/proto-repl-demo/blob/master/dev/user.clj>
(ns user
(:require [clojure.tools.namespace.repl :refer (refresh)]
[calculators.main :as main]
[com.stuartsierra.component :as component]
[clojure.repl :refer (apropos dir doc find-doc pst source)]
;[prc]
;[proto-repl.saved-values]
))
(def system
"A Var containing an object representing the application under
development."
nil)
(defn init
"Creates and initializes the system under development in the Var
#'system."
[]
(println "init")
(alter-var-root #'system
(-> {:web-port 8080}
main/system
constantly)))
(defn start
"Starts the system running, updates the Var #'system."
[]
(println "start")
(alter-var-root #'system component/start))
(defn stop
"Stops the system if it is currently running, updates the Var
#'system."
[]
(alter-var-root #'system #(when % (component/stop %))))
(defn reset []
;(tnr/refresh :after 'user/start)
(println "reset called")
(stop)
(refresh :after 'user/go))
(defn go []
(println "go")
(init)
(start))
(println "dev/user.clj loaded.")
deps.edn
{:deps
{org.clojure/clojure {:mvn/version "1.10.3"}
org.clojure/clojurescript {:mvn/version "1.10.773"}
org.clojure/core.async {:mvn/version "0.3.442"}
com.stuartsierra/component {:mvn/version "1.0.0"}
compojure {:mvn/version "1.6.2"}
ring/ring-core {:mvn/version "1.9.2"}
ring/ring-jetty-adapter {:mvn/version "1.9.2"}
hiccup {:mvn/version "1.0.5"}
optimus {:mvn/version "0.19.2"}
rum {:mvn/version "0.10.8" :exclusions [sablono]}
sablono {:mvn/version "0.8.0"}
org.clojure/tools.namespace {:mvn/version "1.1.0"}
}
:paths
["resources" "src/clj" "src/cljs" "src/cljc"]
:aliases
{:dev {:main-opts ["-m" "cljs.main"
"--compile-opts" "dev.cljs.edn"
"--compile" "calculators.frontend.core"
"--repl"]}
:uberjar
{:replace-deps {com.github.seancorfield/depstar {:mvn/version "2.0.211"}}
:exec-fn hf.depstar/uberjar
:exec-args {:aot true}}}}
OK, so I think itās a bug that it tries to use the main class when :aot true
and :main-class
not specified (thatās the āCompiling nilā issue). I donāt know why adding dev
causes problems but it gives me something to look at.
https://github.com/seancorfield/depstar/issues/76 and https://github.com/seancorfield/depstar/issues/77
For now you have a workaround and youāre able to continue @xavi?
I think I figured out the issue @xavi: because dev/user.clj
is on your default path, Clojure itself runs it when you try to start depstar
ā so :replace-deps
wonāt work here because that removes Component etc from the classpath and dev/user.clj
will not evaluate without it. Iām not sure why you didnāt get a full exception trying to run depstar
in that situation ā hereās what I got:
(! 1137)-> clojure -X:uberjar
Exception in thread "main" Syntax error compiling at (user.clj:1:1).
...
Caused by: java.io.FileNotFoundException: Could not locate com/stuartsierra/component__init.class, com/stuartsierra/component.clj or com/stuartsierra/component.cljc on classpath.
..
at user$eval138$loading__6737__auto____139.invoke(user.clj:2)
When I switched to :extra-deps
, that worked (with the caveat about trying to compile nil
without :main-class
provided).Also, what version of the Clojure CLI are you using? clojure -Sdescribe
Iām on a recent version so I get lots of deprecation warnings about the unqualified lib names:
(! 1148)-> clojure -Sdeps '{:deps {com.github.seancorfield/depstar {:local/root "/Developer/workspace/depstar"}}}' -X hf.depstar/uberjar :aot true :jar test.jar :main-class calculators.main
dev/user.clj loaded.
DEPRECATED: Libs must be qualified, change compojure => compojure/compojure (/Users/sean/clojure/issue-77/deps.edn)
DEPRECATED: Libs must be qualified, change rum => rum/rum (/Users/sean/clojure/issue-77/deps.edn)
DEPRECATED: Libs must be qualified, change sablono => sablono/sablono (/Users/sean/clojure/issue-77/deps.edn)
DEPRECATED: Libs must be qualified, change sablono => sablono/sablono (/Users/sean/clojure/issue-77/deps.edn)
DEPRECATED: Libs must be qualified, change optimus => optimus/optimus (/Users/sean/clojure/issue-77/deps.edn)
DEPRECATED: Libs must be qualified, change hiccup => hiccup/hiccup (/Users/sean/clojure/issue-77/deps.edn)
DEPRECATED: Libs must be qualified, change compojure => compojure/compojure (/Users/sean/clojure/issue-77/deps.edn)
DEPRECATED: Libs must be qualified, change rum => rum/rum (/Users/sean/clojure/issue-77/deps.edn)
DEPRECATED: Libs must be qualified, change sablono => sablono/sablono (/Users/sean/clojure/issue-77/deps.edn)
DEPRECATED: Libs must be qualified, change sablono => sablono/sablono (/Users/sean/clojure/issue-77/deps.edn)
DEPRECATED: Libs must be qualified, change optimus => optimus/optimus (/Users/sean/clojure/issue-77/deps.edn)
DEPRECATED: Libs must be qualified, change hiccup => hiccup/hiccup (/Users/sean/clojure/issue-77/deps.edn)
[main] INFO hf.depstar.uberjar - Compiling calculators.main ...
[main] INFO hf.depstar.uberjar - Building uber jar: test.jar
...
Note the dev/user.clj loaded.
message before the rest of the CLI output.
Iāve fixed #76 on develop (the default branch) and Iāve addressed #77 by adding a note to the README about user.clj
and :replace-paths []
(see notes in that ticket for more details).
You mean why i didn't get an exception saying that the error was in user.clj
like you did?
In my case the error is reported in calculators/web.clj
, which you don't have, and also references GzipHandler and Component. I guess the compiler tried to compile that before user.clj and that's why I got the error there instead.
{:version "1.10.3.814"
...
OK, cool. Just wanted to verify youāre on a recent version, to eliminate other possible weirdness.
Ah, yes, that makes sense.
In my case I don't see it, because for me the exception happens in calculators/web.clj
, which seems to be compiled before user.clj
like we said before
I meant, when the process is successful.
I think just adding :replace-paths []
(per the notes in the GH issue) should solve the problem.
(youāll still end up with dev/user.clj
in your JAR ā and itāll still run in the compilation process inside depstar
ā but that would stop it running in the main depstar
process, which has no other dependencies than depstar
itself, due to :replace-deps
ā does that make sense?)
Yes, :replace-paths []
works ... although like you said before, dev/user.clj
shouldn't be in paths/deps by default, so i'll remove it from there and then there's no need to use :replace-paths []
And yes, although i don't know the full details of how depstar
works, your explanation makes sense to me
Great! Thanks Sean for digging into this, and for all your contributions to the Clojure ecosystem!