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

欢迎!请查阅关于页面获取更多关于如何使用本站的信息。

0
Meta

你好,

我有两个Leiningen项目都能正常编译,并且之前在共享一个公共包含文件中的函数时运行正常。
两个项目都在tomcat服务器上运行

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

另一个项目是一个完整的Clojure web应用程序,也运行在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

和另一个项目错误
原因:java.io.FileNotFoundException: src/sidonie_admin2/sidonie-common.clj (没有该文件或目录类型)

这些错误都是关于在JVM字节码中找不到源文件的同类型错误
我承认,在错误打印堆栈跟踪时,需要提供一些信息,以便给出错误的行号。

所以问题很简单,我如何在两个项目之间共享公共文件且不出现错误?

最好的问候,

Damien

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

2019-10-08 12:40:51.275 SEVERE [http-nio-127.0.0.1-8080-exec-8] org.apache.catalina.core.StandardWrapperValve.invoke 在servlet [eu.oca.ApplicationConfig] 的上下文中,对于[sidereal]抛出异常[org.glassfish.jersey.server.ContainerException: java.lang.ExceptionInInitializerError]根原因
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)

和这

2019-10-08 12:21:42.761 SEVERE [http-nio-127.0.0.1-8080-exec-11] org.apache.catalina.core.StandardContext.listenerStart 在向类监听器实例(监听器)sidonie_admin2.listener发送上下文初始化(context initialized)事件时发生异常
编译时在(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的“checkouts”功能,让它们通过Git依赖公共代码项目。

正如Alex在回答中所说:不要使用 load-file。将通用代码转换成真正的共享代码,您可以通过其命名空间轻松地 :require 它。这意味着需要将共享代码放入每个项目类路径上的格式(通过checkouts或额外的构建步骤来打包通用代码作为JAR)。

+1

你为什么使用 load-file?当clj文件位于jar或war文件内时,您无法将其作为文件加载(在Clojure中使用 load-file 非常有悖常理)。您通常通过 require 将其加载到命名空间中。

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

感谢您的回复,但我不能这样做。事实上,这并不是一个可以放在lib或命名空间中重复使用的库或其它东西,因为我把所有这些都放在了war文件中,而不是将其分开为jar库,使用NetBeans为网站的公共部分服务。开发完受密码保护的网站部分后,我使用了compojure。所以实际上,我可以将所有代码重构成一个单一的单个 .war compojure 文件。但保持现状更快...

所以我找到了这个解决方案,啊,啊,这基本上是一个hack,一个UNIX hack,我承认这一点,为了共享公共文件,我创建了一个符号链接

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

...