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

欢迎!请查看关于页面以了解更多关于此功能的信息。

0

你好,

我有两个编译良好并之前工作正常的项目,我在这两个项目中共享了一些函数的一部分公共包含文件。
这两个项目均在 catalina 服务器上运行

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

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

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 字节数组中缺少源文件!
我承认在错误打印堆栈跟踪时,需要一些信息来给出错误的行号。

所以问题很简单,我如何在这两个项目中共享公共文件并避免错误?

最诚挚的问候,

Daemon

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

2019年10月8日 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)

还有

2019年10月8日 12:21:42.761 SEVERE [http-nio-127.0.0.1-8080-exec-11] org.apache.catalina.core.StandardContext.listenerStart 当向类规范(listener)sidonie_admin2.listener 的实例发送事件时出现错误( történő)上下文初始化
编译时在 (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? 当clojure文件位于jar或war文件内部时,您不能将其作为文件加载(在Clojure中,使用load-file非常不寻常)。您通常加载东西的方式是通过require到命名空间中。

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

感谢您的回复,但我不能这样做。事实上,这并不是一个库或可重用的东西,可以设置为库或者命名空间,我认为,因为我可以把它全部放入war文件中,而不需要使用NetBeans为网站公共部分设置的分离的jar库。在我开发了一个使用compojure的密码保护网站部分之后,实际上我可以一次性在一个compojure的.war文件中重构所有代码。但是保持现状会更快捷...

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

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

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

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

这也适用于硬链接,但我的Dropbox账户不支持硬链接,另外,这个解决方案在Windows环境下也适用,因为它也支持链接。

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

在Emacs中,必须在emacs文件中设置(setq backup-by-copying-when-linked t),以避免Emacs的mv(移动)功能产生的备份文件链接混乱。

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

Daemon

...