我编写了一个 clojure 应用程序,它可以选择加密或解密文件,以及源文件名和目标文件名,并执行指定的操作。我在运行 xubuntu 13、使用 clojure-1.5.1 和 oracle 的 Java SE 7 JDK 的 virtualbox 虚拟机中开发了该应用程序。在那个环境中一切都很好,但是当我将 uberjar 复制到使用 openjdk/jre 7 运行 Xubuntu 12.10 的主机系统时,我在 cli 解析方面得到了一些不同的行为。
1) 如果未指定任何选项,应用程序应打印使用横幅。这在开发环境下正常工作,但在 openjdk 下,抛出 NullPointerException。
2) -v 选项应该打印应用程序的构建版本。同样,这在 devel 环境下工作正常,但在 openjdk/Xubuntu-12.10 下,会抛出一个异常,指出 -v 是一个无效选项。
这是处理 cli 解析的函数(从 -main 调用):
(defn parse-cli
"Parses command line arguments then calls functions based on those arguments. Returns a String or nil if successful."
[args]
(let [[opts files banner]
(cli args
["-h" "--help" "Print this help message." :flag true :default false]
["-v" "--version" "Print build number." :flag true :default false]
["-e" "--encrypt" "Encrypt source file" :flag true :default false]
["-d" "--decrypt" "Decrypt source file" :flag true :default false]
["-k" "--keyfile" "Path to keyfile" :default "./keyfile"])]
(cond (or (true? (:help opts)) (zero? (count args))) banner
(true? (:version opts)) (implementation-version)
:else (let [sfile (first files)
dfile (second files)
cryptoVec (get-cipher-key (:keyfile opts))]
(cond (true? (:encrypt opts)) (if (nil? sfile) "No input file specified"
(if (nil? dfile) "No outputfile specified."
(encrypt-file sfile dfile (first cryptoVec) (second cryptoVec))))
(true? (:decrypt opts)) (if (nil? sfile) "No input file specified"
(if (nil? dfile) "No outputfile specified."
(decrypt-file sfile dfile (first cryptoVec) (second cryptoVec))))
:else "No operation specified.")))))
以下是不带参数运行 uberjar 时的完整异常跟踪:
satch@Ziggy-lin:/media/satch/DATA/.crypto$ java -jar cryptfile.jar
Exception in thread "main" java.lang.NullPointerException
at java.io.FileInputStream.<init>(FileInputStream.java:134)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:525)
at clojure.lang.Reflector.invokeConstructor(Reflector.java:180)
at clojure_crypt_file.core$decrypt_file.invoke(core.clj:40)
at clojure_crypt_file.core$_main.doInvoke(core.clj:81)
at clojure.lang.RestFn.invoke(RestFn.java:397)
at clojure.lang.AFn.applyToHelper(AFn.java:159)
at clojure.lang.RestFn.applyTo(RestFn.java:132)
at clojure_crypt_file.core.main(Unknown Source)
以及使用 -v 选项运行应用程序时的跟踪:
satch@Ziggy-lin:/media/satch/DATA/.crypto$ java -jar cryptfile.jar -v
Exception in thread "main" java.lang.Exception: '-v' is not a valid argument
at clojure.tools.cli$apply_specs.invoke(cli.clj:72)
at clojure.tools.cli$cli.doInvoke(cli.clj:130)
at clojure.lang.RestFn.invoke(RestFn.java:486)
at clojure_crypt_file.core$_main.doInvoke(core.clj:61)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure_crypt_file.core.main(Unknown Source)
应用程序的其余功能在两种环境下均按预期工作。
我假设问题是由 openjdk7 的 jre 和 oracle 的 SE 7 jre 之间的差异引起的,但除此之外我一无所知。具体来说,如果这确实是问题所在,我想找到一种解决这些差异的方法。
最佳答案
好吧,重新编译后,该应用程序现在可以在两种环境中运行。我确实将条件 (false? (count args)) 更改为 (nil?args),但根据文档,这应该以任何一种方式工作(并且在开发环境中做到了)。我对 -v cli 选项没有做任何事情,但该应用程序现在在两种环境中都表现出相同且正确的行为。像这样的事情就是为什么计算机科学是一件让人又爱又恨的事情。 :)
关于clojure uberjar 在 openjdk 上运行时抛出错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17286498/