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

欢迎!请查看关于页面,了解更多关于此如何工作的信息。

0

你好 ,

我有两个 Leiningen 项目,它们可以编译良好,并且在使用一个通用包含文件中的某些函数之前运行良好。
这两个项目都在 tomcat 服务器上运行

第一个项目创建了一个 .jar 文件,用作 Java 代码库,这些代码是从 Java 源代码编译的。
它是用以下方式创建的
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"),在第一个项目中使用 (and 这两个项目都无错误编译)
(load-file "../sidonie-admin2/src/sidonie_admin2/sidonie-common.clj")

错误发生在运行时

问题出在包含在 war 文件和可能不在 jar 文件中的通用定义的文件上,我在运行一个项目时遇到了这个错误
java.io.FileNotFoundException: ../sidonie-admin2/src/sidonie_admin2/sidonie-common.clj

在其他项目中也有这个错误
由: java.io.FileNotFoundException: src/sidonie_admin2/sidonie-common.clj (没有此类型文件或目录)

这是同一类型的错误,抱怨 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 (没有此类型文件或目录)

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 向 sidonie_admin2.listener 类的监听器实例发送初始事件(初始化上下文)时出错
编译时出现语法错误 (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)

由: java.io.FileNotFoundException: src/sidonie_admin2/sidonie-common.clj (没有此类型文件或目录)

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

3 答案

+3

最好的方法可能是将共享代码独立成一个项目,并从中生成一个工件(一个常规的、非uber JAR,但这也意味着您需要在某处发布这些工件——或者在为每个原始项目构建的过程中也构建和本地“安装”共享项目。

或者,可以让两个原始项目都使用Leiningen的“检查出”功能,这样他们就可以通过Git依赖公共代码项目。

正如Alex在他的回答中所说:不要使用load-file。将公共代码转换为真正共享的代码,只需要通过其命名空间来:require。这意味着将共享代码放到一个格式中,以便每个项目都可以将其放在类路径上(通过检查出或额外的构建步骤将公共代码打包为JAR)。

+1

你为什么要使用load-file?当clj文件在jar或war文件内时,您不能将其作为文件加载(在Clojure中使用load-file非常罕见)。您通常通过require将它们导入到一个命名空间中。

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

感谢您的回复,但我不能这样做。实际上,这不是一个库或可重用组件,不能放在库或命名空间中;我认为可以全部放入war文件中,这样就可以不用单独的jar库,在NetBeans中使用公共网站的一部分。之后我又开发了密码保护的网站部分,使用了compojure。所以实际上,我可以在一个单独的compojure.war文件中重写所有代码。但这样速度更快...

因此我找到了这个解决方案,啊哈哈,这基本上是一种黑客手段,我是承认的,为了共享一个公共文件,我创建了一个符号链接

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的 .~ 检查文件功能搅拌链接。

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

Damien

...