clojurefilenotfoundexceptionleiningenslurp

Clojure: War Compilation Failure with Missing Data File Dependency


I am working on an webapp that relies on a certain data file to be slurped at runtime. Without the datafile present I don't seem to be able to compile. Why is this?

This is in my core.clj

(def my-data (slurp "my-file.txt"))

Then when I try to compile:

$ lein ring war

I get this exception

Exception in thread "main" java.io.FileNotFoundException: my-file.txt (No such file or directory), compiling:(core.clj:24:28)

How can I compile my war? I don't need the file to be slurped or even check for existence at compile time. Thanks in advance!

[UPDATE]

This is not specific to war file packaging or ring, for example:

(ns slurp-test.core
    (:gen-class))

(def x (slurp "/tmp/foo.txt"))

(defn -main [& args]
    (println x))

Then:

 $ lein uberjar
 Compiling slurp-test.core
 (ns slurp-test.core
 Exception in thread "main" java.io.FileNotFoundException: /tmp/foo.txt (No such file or directory), compiling:(core.clj:4:8)

How can I fix this?


Solution

  • Compiling a Clojure source file involves evaluating all top-level forms. This is in fact strictly necessary to support the expected semantics -- most notably, macros couldn't work properly otherwise1.

    If you AOT compile your code, top-level forms will be evaluated at compile time, and then again at run time as your compiled code is loaded.

    For this reason, it is generally not a good idea to cause side effects in code living at top level. If an app requires initialization, it should be performed by a function (typically -main).


    1 A macro is a function living in a Var marked as a macro (with :macro true in the Var's metadata; there's a setMacro method on clojure.lang.Var which adds this entry). Macros must clearly be available to the compiler, so they must be loaded at compile time. Furthermore, in computing an expansion, a macro function may want to call non-macro functions or otherwise make use of the values of arbitrary Vars resulting from evaluating any top-level code occurring before the point where the macro is invoked. Removing these capabilities would cripple the macro facility rather badly.