2024 年 Clojure 状况调查!分享您的想法。

欢迎!请参阅关于页面以了解更多关于如何使用本网站的信息。

0
元数据

嗨,

我有两个 Leiningen 项目,它们可以编译良好,并在将一些函数放入一个共同的包含文件之前工作正常。
这两个项目都在 tomcat 服务器上运行

第一个项目创建了一个包含用于从 Java 源编译的 Java 代码的库的 .jar 文件。
它使用以下方式创建的
lein new eu.oca.jclojure
并以这种方式编译
lein uberjar

另一个项目是一个完整的 Clojure 网络应用程序,也运行在 tomcat 上。
它使用以下方式创建的

lein new compojure sidonie-admin

并使用以下方式编译
lein ring uberwar

共同文件以这种方式包含在源 Clojure 代码中

(load-file "src/sidonie_admin2/sidonie-common.clj") 在第二个项目中,以及在第一个项目中如下 (并且两个都没有错误编译)
(load-file "../sidonie-admin2/src/sidonie_admin2/sidonie-common.clj")

错误发生在运行时

问题出在这个文件有共同的定义没有被包含在 war 文件中,可能也没有在 jar 文件中,并且当运行一个项目时我出现了这个错误
java.io.FileNotFoundException: ../sidonie-admin2/src/sidonie_admin2/sidonie-common.clj

并与其他项目一起出现此错误
Caused by: java.io.FileNotFoundException: src/sidonie_admin2/sidonie-common.clj (Aucun fichier ou dossier de ce type)

这些是相同类型的错误,抱怨缺少 JVM 字节码中的源文件!
我必须承认,在出错时打印堆栈跟踪需要一些信息来提供错误行号。

所以问题很简单,我如何在没有错误的情况下在这两个项目中共享公共文件?

此致

Damien

以下是一些服务器日志输出

08-Oct-2019 12:40:51.275 SEVERE [http-nio-127.0.0.1-8080-exec-8] org.apache.catalina.core.StandardWrapperValve.invoke Servlet.service() for servlet [eu.oca.ApplicationConfig] in context with path [/Sidonie] threw exception [org.glassfish.jersey.server.ContainerException: java.lang.ExceptionInInitializerError] with root cause
java.io.FileNotFoundException: ../sidonie-admin2/src/sidonie_admin2/sidonie-common.clj (Aucun fichier ou dossier de ce type)

at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.<init>(FileInputStream.java:138)
at java.io.FileInputStream.<init>(FileInputStream.java:93)
at clojure.lang.Compiler.loadFile(Compiler.java:7314)
at clojure.lang.RT$3.invoke(RT.java:320)
at eu.oca.jclojure__init.load(Unknown Source)
at eu.oca.jclojure__init.<clinit>(Unknown Source)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at clojure.lang.RT.classForName(RT.java:2168)
at clojure.lang.RT.classForNam

...

un(NioEndpoint.java:1500)

at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1456)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)

并且还有

08-Oct-2019 12:21:42.761 SEVERE [http-nio-127.0.0.1-8080-exec-11] org.apache.catalina.core.StandardContext.listenerStart Exception lors de l'envoi de l'évènement contexte initialisé (context initialized) à l'instance de classe d'écoute (listener) sidonie_admin2.listener
Syntax error compiling at (sidonie_admin2/handler.clj:32:1).

at clojure.lang.Compiler.load(Compiler.java:7647)
at clojure.lang.RT.loadResourceScript(RT.java:381)
at clojure.lang.RT.loadResourceScript(RT.java:372)
at clojure.lang.RT.load(RT.java:463)
at clojure.lang.RT.load(RT.java:428)
at clojure.core$load$fn__6824.invoke(core.clj:6126)
at clojure.core$load.invokeStatic(core.clj:6125)
at clojure.core$load.doInvo

...

at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1500)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1456)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)

Caused by: java.io.FileNotFoundException: src/sidonie_admin2/sidonie-common.clj (Aucun fichier ou dossier de ce type)

at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInp

3 个答案

+3

最好的方案可能是将共享代码转换成自己的项目,并从此项目中生成一个工件(一个常规的非“超级”JAR),但这意味着你需要在某处发布工件——或者使每个原始项目的构建过程也构建并“安装”本地共享项目。

或者,你可以让两个原始项目都使用 Leiningen 的“检出”功能,以便它们通过 Git 依赖共同的代码项目。

正如 Alex 在他的答案中所说:不要使用 load-file。将共享代码转换成真正共享的形式,并通过其命名空间简单地使用 :require。这意味着需要将共享代码格式化,使其位于每个项目的类路径上(通过检出或额外的构建步骤将共享代码打包为一个 JAR)。

+1

你为什么要使用 load-file?当 clj 文件位于 jar 或 war 文件中时,你不能将其作为文件加载(并且使用 load-file 在 Clojure 中是非常不寻常的)。你通常会通过 require 将它们加载到命名空间中。

他使用 load-file 是因为他尝试在两个项目之间共享源代码。
0

感谢您的回复,但我不能这样进行。事实上,这并不是一个库或可重用的东西,可以放入库或命名空间中,我认为是这样,因为我可以把所有东西都放在.war 文件中,而不需要使用在 NetBeans 中的单独的 jar 库,用于网站公开部分。在我开发完一个使用 Compojure 的受密码保护的网站部分之后,实际上我可以在单个 .war Compojure 文件中重新编写所有代码。但这更简单快速...

所以我找到了这个解决方案,嘿嘿,这基本上是一个“黑客”方法,我承认这是一个 UNIX “黑客”方法,为了共享常用的文件,我创建了一个符号链接

ln -s ../../../../sidonie-admin2/src/sidonie_admin2/sidonie-common.clj symbolic-link-sidonie-common.clj

并且我稍微改变了加载文件的方式,不再使用 load-file,而是使用 load

(load "symbolic-link-sidonie-common")

也可以与硬链接一起使用,但我的 Dropbox 账户不支持硬链接,此外,这个解决方案在 Windows 下也应该有效,因为它也支持链接。

所以我可以编辑一个在许多项目中共享的简单文件,并且我可以从任何目录中进行编辑。

在 emacs 中,必须在 .emacs 中设置 (setq backup-by-copying-when-linked t),以避免 emacs 的 .~ 后缀备份文件的 mv(移动)功能,这会给链接带来混乱。

我承认这不是一个完美的解决方案,但问题本身也不是完美的 ;-)

Damien

...