如何从 Clojure 程序中访问 JAR 类?
我已经被困在一些我以前曾经工作过的事情上好几天了。知道我可能错过了一些明显的东西。任何帮助将不胜感激。
在我的 Clojure 程序中,我想访问最初用 Java 编写的类中的方法。让我们使用一个具体的例子:org.infoml.jaxb.ObjectFactory。这些类位于 .jar 文件 (infoml-classes-1.0.jar
) 中,该文件是一个可双击的 Java 应用程序。如果打开 jar 文件,您会看到 Java 类包的顶级段的文件夹:
macscooter:infoml-classes-1.0 folder gw$ find . -print | sed -e 's;[^/]*/;|____;g;s;____|; |;g'
.
|____META-INF
| |____MANIFEST.MF
|____org
| |____infoml
| | |____infocardOrganizer <<<<<< Java application's classes
| | | |____AFileFilter.class
| ... many classes omitted here
| | | |____UniqueContentListener.class
| | | |____UniqueContentModel.class
| | |____jaxb
| | | |____AgentContainerLocationType.class
| | | |____AgentType.class
| ... many classes omitted here
| | | |____ObjectFactory.class <<<<<< HERE IT IS
| ... many classes omitted here
| | | |____TableRowType.class
| | | |____TableType.class
macscooter:infoml-classes-1.0 folder gw$
在我的 Clojure 程序中,我导入它(从文件 cardmaker.clj
):
(ns infwb.cardmaker
(:gen-class)
(:import
(javax.xml.bind JAXBContext JAXBException Marshaller
Unmarshaller)
(org.infoml.jaxb ContentAgentContainerLocationType
InfomlFile InfomlType ObjectFactory PType <<<<<< HERE IT IS
RichTextWithExactType
SelectorsType
SimpleRichTextType)
(java.io ByteArrayOutputStream IOException)))
当我打印出 REPL 看到的类路径,它就在那里(如 infoml-classes-1.0.jar
):
infwb.cardmaker> (doseq [p (.getURLs (java.lang.ClassLoader/getSystemClassLoader))] (println (.getPath p)))
/Users/gw/tech/clojurestuff/cljprojects/infwb/src/
/Users/gw/tech/clojurestuff/cljprojects/infwb/test/
/Users/gw/tech/clojurestuff/cljprojects/infwb/classes/
/Users/gw/tech/clojurestuff/cljprojects/infwb/lib/clojure-1.3.0-SNAPSHOT.jar
/Users/gw/tech/clojurestuff/cljprojects/infwb/lib/clojure-contrib-1.2.0.jar
/Users/gw/tech/clojurestuff/cljprojects/infwb/lib/infoml-classes-1.0.jar <<<<<< HERE IT IS
/Users/gw/tech/clojurestuff/cljprojects/infwb/lib/piccolo2dcore-1.3.jar
/Users/gw/tech/clojurestuff/cljprojects/infwb/lib/piccolo2dextras-1.3.jar
/Users/gw/tech/clojurestuff/cljprojects/infwb/lib/sxqj-beta2.jar
/Users/gw/tech/clojurestuff/cljprojects/infwb/lib/dev/clojure-1.2.0.jar
/Users/gw/tech/clojurestuff/cljprojects/infwb/lib/dev/swank-clojure-1.3.0-20110104.084027-21.jar
nil
infwb.cardmaker>
但是,当我尝试编译文件 cardmaker.clj 时(通过 Cc Ck 或 (加载文件“src/infwb/cardmaker.clj”)
,我得到以下异常:
Could not initialize class org.infoml.jaxb.ObjectFactory
[Thrown class java.lang.NoClassDefFoundError]
我已经重新启动我的机器以尝试消除作为问题根源的无意的污垢。我在互联网上研究了一些东西——没有运气,我查看了 MANIFEST.MF 文件来寻找线索,并将 jar 文件精简为我需要的类——现在我已经在它上面睡了两次了。没有解决方案。
使用 Clojure 中的现有 Java 类是一件有用的事情,我很感激任何人都可以给我的帮助。谢谢。
我的问题是由多种因素引起的。 @kotarak 的回答很准确。谢谢。
I've been stuck for several days on something that I know I've gotten to work once before. I'm probably missing something obvious. Any help would be appreciated.
In my Clojure program, I want to access methods from classes originally written in Java. Let's use a specific example: org.infoml.jaxb.ObjectFactory. These classes are in a .jar file (infoml-classes-1.0.jar
) that is a double-clickable Java application. If you open up the jar file, you see the folder for the top-level segment of the Java classes' package:
macscooter:infoml-classes-1.0 folder gw$ find . -print | sed -e 's;[^/]*/;|____;g;s;____|; |;g'
.
|____META-INF
| |____MANIFEST.MF
|____org
| |____infoml
| | |____infocardOrganizer <<<<<< Java application's classes
| | | |____AFileFilter.class
| ... many classes omitted here
| | | |____UniqueContentListener.class
| | | |____UniqueContentModel.class
| | |____jaxb
| | | |____AgentContainerLocationType.class
| | | |____AgentType.class
| ... many classes omitted here
| | | |____ObjectFactory.class <<<<<< HERE IT IS
| ... many classes omitted here
| | | |____TableRowType.class
| | | |____TableType.class
macscooter:infoml-classes-1.0 folder gw$
In my Clojure program, I import it (from file cardmaker.clj
):
(ns infwb.cardmaker
(:gen-class)
(:import
(javax.xml.bind JAXBContext JAXBException Marshaller
Unmarshaller)
(org.infoml.jaxb ContentAgentContainerLocationType
InfomlFile InfomlType ObjectFactory PType <<<<<< HERE IT IS
RichTextWithExactType
SelectorsType
SimpleRichTextType)
(java.io ByteArrayOutputStream IOException)))
When I print out the classpath that the REPL sees, it's there (as infoml-classes-1.0.jar
):
infwb.cardmaker> (doseq [p (.getURLs (java.lang.ClassLoader/getSystemClassLoader))] (println (.getPath p)))
/Users/gw/tech/clojurestuff/cljprojects/infwb/src/
/Users/gw/tech/clojurestuff/cljprojects/infwb/test/
/Users/gw/tech/clojurestuff/cljprojects/infwb/classes/
/Users/gw/tech/clojurestuff/cljprojects/infwb/lib/clojure-1.3.0-SNAPSHOT.jar
/Users/gw/tech/clojurestuff/cljprojects/infwb/lib/clojure-contrib-1.2.0.jar
/Users/gw/tech/clojurestuff/cljprojects/infwb/lib/infoml-classes-1.0.jar <<<<<< HERE IT IS
/Users/gw/tech/clojurestuff/cljprojects/infwb/lib/piccolo2dcore-1.3.jar
/Users/gw/tech/clojurestuff/cljprojects/infwb/lib/piccolo2dextras-1.3.jar
/Users/gw/tech/clojurestuff/cljprojects/infwb/lib/sxqj-beta2.jar
/Users/gw/tech/clojurestuff/cljprojects/infwb/lib/dev/clojure-1.2.0.jar
/Users/gw/tech/clojurestuff/cljprojects/infwb/lib/dev/swank-clojure-1.3.0-20110104.084027-21.jar
nil
infwb.cardmaker>
However, when I try to compile the file cardmaker.clj (by either C-c C-k or (load-file "src/infwb/cardmaker.clj")
, I get the following exception:
Could not initialize class org.infoml.jaxb.ObjectFactory
[Thrown class java.lang.NoClassDefFoundError]
I've gone as far as rebooting my machine to try to eliminate inadvertent crud as a source of the problem. I've researched several things on the Internet--no luck. I've looked at the MANIFEST.MF file for clues, and stripped the jar file down to just the classes I need. I've slept on it overnight twice now--still no solution.
Using existing Java classes from within Clojure is a useful thing to do. I'd appreciate the help that anyone might be able to give me. Thanks.
ADDENDUM: My problem was caused by a number of factors, including a missing jar file. @kotarak's answer was spot on. Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我不是 100% 确定我完全理解你的问题,但如果你只是尝试从 Clojure 程序访问你的 Java 类,我会使用 leiningen。安装 leiningen 后大致执行以下操作:
将 jar 文件放入 lib 目录中。
之后,您将获得如下所示的目录结构:
现在您可以在 Clojure 程序中导入 Java 类,并通过 Clojure Java 互操作访问它们。这是一个示例
要运行该程序,您有很多不同的选项。请参阅 leiningen 文档。看起来您正在使用 emacs,因此请参阅 swank clojure。以这种方式使用 leiningen 应该可以解决您的类路径问题。
I am not 100% sure I fully get your question, but if you are simply trying to access your Java classes from a Clojure program, I would use leiningen. Here is roughly what you do once you have installed leiningen:
Put your jar file in the lib directory.
After this you will get a directory structure that looks like this:
Now you can import your Java classes in your Clojure program and have access to them via Clojure Java interop. Here is an example
To run this program, you have a bunch of different options. See the leiningen docs. It looks like you are using emacs so see swank clojure. Using leiningen in this way should resolve your classpath issues.
您
导入
类的方式很好。显然,ObjectFactory
类无法初始化,因为它需要的其他一些类不在类路径上。查找完整的堆栈跟踪,找出ObjectFactory
缺少哪个类才能正常工作。正如 @mikera 建议的那样,您可以在 Repl 中使用(import 'org.infoml.jaxb.ObjectFactory)
来执行此操作。 (除非 emacs 吃掉你的堆栈跟踪......)The way you
import
the classes is fine. Obviously theObjectFactory
class cannot be initialised because some other class it needs is not on the classpath. Lookup at the full stacktrace to find out which class is missing forObjectFactory
to work. As @mikera suggested, you can use(import 'org.infoml.jaxb.ObjectFactory)
in the Repl to do that. (Unless emacs eats your stacktrace...)我使用以下代码导入 Java 类: 如果
相关的 Java 类位于类路径上(如果它们位于 .jar 中就可以了),那么这应该可以工作。
要测试它们是否在类路径上,您还可以在 REPL 中执行以下操作:
I use the following code to import Java classes:
This should work providing the relevant Java classes are on the classpath (it's fine if they are in a .jar).
To test whether these are on the classpath you can also do the following at the REPL: