Uberjar with depstar

Hi All,
I have a project using Clojure cli tools clj and deps.edn. I use @seancorfield depstar to build an uber jar:

 :uberjar {:extra-deps {seancorfield/depstar {:mvn/version "1.0.94"}} 
              :extra-paths ["resources"] 
              :main-opts ["-m" "hf.depstar.uberjar" "foo.jar"
                            "-C" "-m" "foo.core"]}

I have a resources folder at the root of my project that contains files read by functions in my code. I expected the uberjar to include the resources folder as is in the jar, but the contents are copied at the root of jar when inspecting it with jar -tf foo.jar. Which means (-> "resources/conf.edn" slurp ...) fails with java.io.FileNotFoundException: resources/conf.edn when running the jar produced with uberjar.
What can I do to access the files in the resources folder when using the repl and when the code references the files when executing the jar.
What do you recommend.
Thanks in advance.

That is the correct behavior. You would normally have src and resources on your classpath for development and use io/resource to access files via their relative path from the classpath.

slurp is going to try to read from the file system if you just give it a string – which won’t read files from the classpath anyway since it will try to read files outside of the JAR file. slurp would read (external) files relative to wherever the JAR was run.

Here’s a REPL session that might help clarify this:

user=> (require '[clojure.java.io :as io])
user=> (io/resource "deps.edn") ; deps.edn is not on the classpath...
nil ; ... so this returns nil
user=> (slurp "deps.edn") ; slurp can read it from the current directory:
"{:aliases\n {:test-deps\n  {:extra-deps\n   {bidi/bidi {},\n..."

user=> (io/resource "wsadmin.edn") ; wsadmin.edn is on my classpath...
#object[java.net.URL 0xf26cd76 "file:/Developer/workspace/wsmain/clojure/wsadmin-auth/resources/wsadmin.edn"] ; ...so this returns non-nil...
user=> (slurp (io/resource "wsadmin.edn")) ; ...and I can slurp from a resource...
"{:azure {:client-id \"...\"\n         :secret \"...\"\n         :tenant-name \"...\"\n..."

user=> (slurp "wsadmin.edn") ; wsadmin.edn is not in the current directory...
;; ...so this fails:
Execution error (FileNotFoundException) at java.io.FileInputStream/open0 (FileInputStream.java:-2).
wsadmin.edn (No such file or directory)

It works great. Thank you !

I wrongly expected … :slight_smile:

No worries: the difference between files and resources tends to catch almost everyone out when they first start building uberjars with Clojure (with Leiningen, with Boot, or with depstar).

1 Like