Scala / Clojure interop在PC上工作但在另一个上使用java.lang.ExceptionInInitializerError失败

时间:2012-03-26 17:33:35

标签: java scala clojure interop leiningen

我有一个用Java / Scala混合编写的项目,我在其中调用由Clojure生成的类(ca.gsimard.spacecraft.client.clojail)公开的静态方法(epadEval)。

在clojail.clj中:
(与Leinengen汇编成一个独立的罐子:“lein uberjar”)

(ns ca.gsimard.spacecraft.client.clojail
  (:use [clojail core testers])
  (:gen-class
    :name ca.gsimard.spacecraft.client.clojail
    :methods [#^{:static true} [epadEval [String] String]]))

(defn -epadEval
  "Evaluate string s within a clojail sandbox."
  [s]
  (let [writer (java.io.StringWriter.)]
    (*sb* (safe-read (str "(print " s ")")) {#'*out* writer})
    (str writer)))

在main.scala中:
(在我导入之前由Leinengen生成的.jar的Eclipse项目中):

import ca.gsimard.spacecraft.client.clojail
println("Epad: " + clojail.epadEval("(+ 1 2 3)"))

我通过构建一个胖罐来部署项目并运行它:

在PC1(Linux)上:

Epad: 6

在PC2(Windows 7)上:

Exception in thread "main" java.lang.ExceptionInInitializerError
    at clojure.lang.Namespace.<init>(Namespace.java:34)
    at clojure.lang.Namespace.findOrCreate(Namespace.java:176)
    at clojure.lang.Var.internPrivate(Var.java:149)
    at ca.gsimard.spacecraft.client.clojail.<clinit>(Unknown Source)
    at ca.gsimard.spacecraft.client.Epad$.eval(EpadClient.scala:78)
    at ca.gsimard.spacecraft.client.Main$.main(MainClient.scala:25)
    at ca.gsimard.spacecraft.client.Main.main(MainClient.scala)
Caused by: java.lang.NullPointerException
    at clojure.core$eval1697$fn__1698.invoke(core.clj:6135)
    at clojure.core$eval1697.invoke(core.clj:6135)
    at clojure.lang.Compiler.eval(Compiler.java:6465)
    at clojure.lang.Compiler.load(Compiler.java:6902)
    at clojure.lang.RT.loadResourceScript(RT.java:357)
    at clojure.lang.RT.loadResourceScript(RT.java:348)
    at clojure.lang.RT.load(RT.java:427)
    at clojure.lang.RT.load(RT.java:398)
    at clojure.lang.RT.doInit(RT.java:434)
    at clojure.lang.RT.<clinit>(RT.java:316)
    ... 7 more

我对发生的事情毫无头绪:我所知道的是,发生的事情并不多。看起来Clojure类甚至没有加载。在(ns ..)和(defn ..)之间添加(println ..)命令不会在PC2上打印任何内容,因此问题似乎是在加载时,而不是在调用时。

<击>

请注意,在失败的同一台Windows7计算机上,我可以使用(-main)方法调用(-epadEval ..)成功构建并运行仅限Clojure的独立uberjar。

知道这里发生了什么吗?

编辑:我已经按照下面的建议运行了 java -verbose 。根据我的理解,函数 epadEval 在被定义之前被调用!当JVM仍在加载 clojure.core 时发生异常。在此之前我没有看到任何 [Loaded ca.gsimard.spacecraft.client.clojail ...]

[Loaded clojure.core$eval1697$fn__1698 from __JVM_DefineClass__]
[Loaded clojure.core$eval1697 from __JVM_DefineClass__]
Exception in thread "main" [Loaded java.lang.Throwable$PrintStreamOrWriter from
C:\Program Files\Java\jre7\lib\rt.jar]
[Loaded java.lang.Throwable$WrappedPrintStream from C:\Program Files\Java\jre7\lib\rt.jar]
[Loaded java.util.IdentityHashMap$KeySet from C:\Program Files\Java\jre7\lib\rt.jar]
java.lang.ExceptionInInitializerError
    at clojure.lang.Namespace.<init>(Namespace.java:34)
    at clojure.lang.Namespace.findOrCreate(Namespace.java:176)
    at clojure.lang.Var.internPrivate(Var.java:149)
    at ca.gsimard.spacecraft.client.clojail.<clinit>(Unknown Source)
    at ca.gsimard.spacecraft.client.Epad$.eval(EpadClient.scala:78)
    at ca.gsimard.spacecraft.client.Main$.main(MainClient.scala:25)
    at ca.gsimard.spacecraft.client.Main.main(MainClient.scala)
[Loaded java.util.Objects from C:\Program Files\Java\jre7\lib\rt.jar]
Caused by: java.lang.NullPointerException
    at clojure.core$eval1697$fn__1698.invoke(core.clj:6135)
    at clojure.core$eval1697.invoke(core.clj:6135)
    at clojure.lang.Compiler.eval(Compiler.java:6465)
    at clojure.lang.Compiler.load(Compiler.java:6902)
    at clojure.lang.RT.loadResourceScript(RT.java:357)
    at clojure.lang.RT.loadResourceScript(RT.java:348)
    at clojure.lang.RT.load(RT.java:427)
    at clojure.lang.RT.load(RT.java:398)
    at clojure.lang.RT.doInit(RT.java:434)
    at clojure.lang.RT.<clinit>(RT.java:316)
    ... 7 more
[Loaded java.lang.Shutdown from C:\Program Files\Java\jre7\lib\rt.jar]
[Loaded java.lang.Shutdown$Lock from C:\Program Files\Java\jre7\lib\rt.jar]

在有人问之前,是的,这个应用程序中有多个线程(使用Akka Actors),是的,对epadEval的调用是从这样一个actor的 receive 函数完成的。运行Windows 7(崩溃的地方)的PC比运行Linux的2核笔记本电脑(这不会崩溃)拥有更多内核。我的猜测是,我现在只是在笔记本电脑上的线程中一直很幸运。

  • 这个猜测有意义吗?
  • 在某些线程尝试调用其中一个静态函数之前,如何确保 clojail 类已完全加载?

3 个答案:

答案 0 :(得分:2)

如另一个答案所述,这几乎肯定是环境差异。

以详细模式运行java,如下所示:

java -verbose -jar project.jar

将提供有关类加载的大量信息。幸运的是,您可以在异常发生之前立即推断出一些有用的信息。

答案 1 :(得分:0)

99%的时间这些问题是由于一台机器与另一台机器之间的环境差异造成的。你没有提到IDE(如果有的话 - 是Eclipse吗?)

检查您的JVM版本并确保使用您认为自己的JVM非常重要。例如,您可以在Linux上使用openJDK,在Windows上使用Oracle JDK。 在两台机器上运行java --version以检查配置。

请发布有关您的配置的更多信息,以便我们进一步提供帮助。

答案 2 :(得分:0)

Akka使用当前的Thread(创建ActorSystem的线程)上下文类加载器(如果有的话)。可以在这里玩吗?