Clojure: how to get the path to the running JAR / root source directory?

There is an easy way in Java to get the path to the running jar file:

MyClass.class.getProtectionDomain().getCodeSource().getLocation().getPath() 

But in Clojure we do not have a class name , but only a namespace and function. The same goes for uncompressed / REPL scripts.

So my questions are:

  • How to find the path to the running jar file ?
  • How to find the path to uncompressed source files ?
+8
jar path clojure
source share
6 answers

By default, the name of your class is the name of your AOT-compiled namespace (for this gen-class class), so you can simply use the namespace class.

 (ns foo.core (:gen-class)) (defn this-jar "utility function to get the name of jar in which this function is invoked" [& [ns]] (-> (or ns (class *ns*)) .getProtectionDomain .getCodeSource .getLocation .getPath)) (defn -main [& _] (println (this-jar foo.core))) 

The result of work:

 $ java -cp foo-0.1.0-SNAPSHOT-standalone.jar foo.core /home/rlevy/prj/foo/target/foo-0.1.0-SNAPSHOT-standalone.jar 
+5
source share

The idea of ​​classpath is to hide classes. You can have classes with the same name loaded from different class loaders, you can have the same class in several jars and rely on ordering the class path to choose the right one.

Why do you want to know? If this is for any other reason than debugging / recording, you are on dangerous ground and should be tested carefully.

It is actually perfectly reasonable if the classes do not have a jar file. This can happen in java for any classes generated at runtime (think proxies).

In clojure, a simple example would be as shown in the replication session below ... You will see that the @mikera clause works fine for clojure.lang.Atom , which is a built-in class. But when you use deftype to create your own type, clojure creates the class and has no place ...

 user> (prn (-> clojure.lang.Atom (.getProtectionDomain) (.getCodeSource) (.getLocation))) #<URL file:/workspace/clj-scratch/lib/clojure-1.3.0.jar> nil user> (deftype Foo []) user.Foo user> (prn (-> (Foo.) (.getClass) (.getProtectionDomain) (.getCodeSource) (.getLocation))) nil nil user> 
+2
source share

I have not tried this, but it seems that all you need is an instance of the class. So, for example, you cannot do this:

 (-> (new Object) (.getClass) (.getProtectionDomain) (.getCodeSource) (.getLocation) (.getPath)) 
+1
source share

You can try to get the path from a class defined by Clojure itself, for example:

 (-> clojure.lang.Atom (.getProtectionDomain) (.getCodeSource) (.getLocation)) => file:/some/path/to/clojure-1.3.0.jar 

I believe this is a technically launched jar file if you use Clojure scripts or coding in REPL.

+1
source share

find source files in the bank: tools.namespace / clojure-sources-in-jar

0
source share
 (defn this-jar "utility function to get the name of jar in which this function is invoked" [& [ns]] (-> (or ns (class *ns*)) .getProtectionDomain .getCodeSource .getLocation .toURI .getPath)) 

Please note that it is very important to call .toURI in order to avoid problems with paths that have spaces, as described in the equivalent Java question: How to get the path to the running JAR file? .

0
source share

All Articles