Path Clojure:如何获取正在运行的JAR/根源目录的路径?

Path Clojure:如何获取正在运行的JAR/根源目录的路径?,path,jar,clojure,Path,Jar,Clojure,在Java中,有一种获取运行jar文件路径的方法: MyClass.class.getProtectionDomain().getCodeSource().getLocation().getPath() 但是在Clojure中,我们没有类名,只有名称空间和函数。同样的情况也适用于未编译的脚本/REPL 因此,我的问题是: 如何找到运行jar文件的路径 如何找到未编译源文件的路径 我还没有尝试过这个,但您似乎只需要一个类实例。例如,你不能这样做: (-> (new Object) (.ge

在Java中,有一种获取运行jar文件路径的方法:

MyClass.class.getProtectionDomain().getCodeSource().getLocation().getPath()
但是在Clojure中,我们没有类名,只有名称空间和函数。同样的情况也适用于未编译的脚本/REPL

因此,我的问题是:

  • 如何找到运行jar文件的路径
  • 如何找到未编译源文件的路径

  • 我还没有尝试过这个,但您似乎只需要一个类实例。例如,你不能这样做:

    (-> (new Object) (.getClass) (.getProtectionDomain) (.getCodeSource) (.getLocation) (.getPath))
    

    您可以尝试从Clojure本身定义的类获取路径,例如:

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

    如果您在REPL上运行Clojure脚本或编码,我相信从技术上讲,这就是正在运行的jar文件。

    类路径的思想是隐藏类的来源。您可以从不同的类加载器中加载具有相同名称的类,也可以在多个JAR中加载相同的类,并依靠类路径排序来选择正确的类

    你为什么想知道?如果是出于调试/记录目的以外的任何其他原因,您的处境很危险,应该小心行事

    事实上,类没有jar文件是完全合理的。在java中,任何运行时生成的类(比如代理)都可能发生这种情况

    在clojure中,一个简单的示例如下repl会话所示。。。您将看到@mikera的建议对于内置类
    clojure.lang.Atom
    非常有效。但是,当您使用
    deftype
    创建自己的类型时,clojure会生成一个类,而它没有位置

    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> 
    

    user>(prn(->clojure.lang.Atom
    (.getProtectionDomain)
    (.getCodeSource)
    (.getLocation)))
    #
    无
    用户>(deftype Foo[]
    user.Foo
    用户>(prn(->(Foo.)
    (.getClass)
    (.getProtectionDomain)
    (.getCodeSource)
    (.getLocation)))
    无
    无
    用户>
    
    在jar中查找源文件:

    默认情况下,类的名称是AOT编译的命名空间的名称(这就是gen类的用途),因此您可以简单地使用命名空间的类

    (ns foo.core
      (:gen-class))
    
    (defn this-jar
      "utility function to get the name of jar in which this function is invoked"
      [& [ns]]
      ;; The .toURI step is vital to avoid problems with special characters,
      ;; including spaces and pluses.
      ;; Source: https://stackoverflow.com/q/320542/7012#comment18478290_320595
      (-> (or ns (class *ns*))
          .getProtectionDomain .getCodeSource .getLocation .toURI .getPath))
    
    (defn -main [& _]
      (println (this-jar foo.core)))
    
    运行结果:

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

    请注意,调用
    .toURI
    非常重要,以避免出现类似Java问题中描述的带有空格的路径问题:。

    不幸的是,no-
    。getCodeSource
    返回
    nil
    和所有断链。技术上运行的程序驻留在内存中:)我需要jar/源的路径。用户可以将
    clojure.jar
    与我的代码分开放置,并通过
    classpath
    链接它,因此我的程序仍然不知道它位于何处。如果您想找到此路径以定位资源(如图像等),可以将它们打包到jar中。Java有一个API来访问打包在JAR中的资源文件。@AlexD:图像等资源不是唯一可能的用途。我可能需要运行单独的命令行程序和JAR/脚本,或者我可能需要它在系统中注册我的程序。还有一些框架依赖于文件系统中的实际路径,而不是JAR中的URI。我了解所有这些,但我并不限制Java类加载器的可能方法——Clojure可能有自己的方法来定位运行中的文件。例如,当某个函数抛出异常时,Clojure运行时会打印stacktrace,其中包含所有相应文件的名称。因此,我相信有一些(可能不是很严格)方法可以从脚本中获取这些信息。将类放入JVM的唯一方法是通过类加载器。clojure不能提供其他方法,因为JVM出于安全原因阻止它。clojure中的堆栈跟踪是JVM堆栈跟踪。类的动态生成是clojure堆栈跟踪如此难以解释的原因。e、 g.在REPL中计算表单会导致生成一个没有底层源的类-因此在这种情况下,您会得到一个没有文件信息的堆栈元素…
    。clj
    文件不是类,因此Clojure运行时本身会跟踪它。主要的一点是,JVM或Clojure运行时总是知道从何处加载代码。Clojure使用ClassLoader#getResource()/ClassLoader#getSystemResource()和friends加载资源(即clj文件),所以同样,这都是关于类路径的……我感兴趣的是如何找到JAR文件或解压缩的.clj文件的路径,例如,获取运行代码的路径,而不是如何在特定的JAR archive中查找.clj文件。在dir中查找源文件?使用tools.namespace/find-clojure-sources-in-dir函数。我需要找到运行代码的路径。我不知道项目的目录甚至结构,我只知道程序中的当前点,我想知道代码(源代码或编译代码)在哪里。例如,我想找到另一个文件,该文件与我的函数文件位于同一目录中。但我的函数可能位于.clj文件、编译的.class或.jar内部,它通过-cp选项与其他jar分开添加到类路径中。我不知道我的函数的用户将如何将其添加到项目中。他甚至可以重命名我的.clj文件,但我的函数仍然应该找到正确的位置。该函数将编译为类,如果AOT编译,我可以获取路径。该类的名称是什么(请注意,您应该在代码中获取它,而不仅仅是在文件系统中)?如果它不会被AOT编译呢?我对基于Clojure的方式感兴趣,这种方式可以在Clojure代码中安全使用,并且总是产生正确的结果。
    (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))