如何从 Clojure 程序中访问 JAR 类?

发布于 2024-11-14 07:53:12 字数 3020 浏览 2 评论 0原文

我已经被困在一些我以前曾经工作过的事情上好几天了。知道我可能错过了一些明显的东西。任何帮助将不胜感激。

在我的 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

话少情深 2024-11-21 07:53:12

我不是 100% 确定我完全理解你的问题,但如果你只是尝试从 Clojure 程序访问你的 Java 类,我会使用 leiningen。安装 leiningen 后大致执行以下操作:

lein new cardmaker
cd cardmaker
lein deps

将 jar 文件放入 lib 目录中。

之后,您将获得如下所示的目录结构:

├── README
├── classes
├── lib
│   ├── clojure-1.2.1.jar
│   └── infoml-classes-1.0.jar
├── project.clj
├── src
│   └── cardmaker
│       └── core.clj
└── test
    └── cardmaker
        └── test
            └── core.clj

现在您可以在 Clojure 程序中导入 Java 类,并通过 Clojure Java 互操作访问它们。这是一个示例

(ns cardmaker.core
  (:import [java.util Blah Blah]))

要运行该程序,您有很多不同的选项。请参阅 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:

lein new cardmaker
cd cardmaker
lein deps

Put your jar file in the lib directory.

After this you will get a directory structure that looks like this:

├── README
├── classes
├── lib
│   ├── clojure-1.2.1.jar
│   └── infoml-classes-1.0.jar
├── project.clj
├── src
│   └── cardmaker
│       └── core.clj
└── test
    └── cardmaker
        └── test
            └── core.clj

Now you can import your Java classes in your Clojure program and have access to them via Clojure Java interop. Here is an example

(ns cardmaker.core
  (:import [java.util Blah Blah]))

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.

只是在用心讲痛 2024-11-21 07:53:12

导入类的方式很好。显然,ObjectFactory 类无法初始化,因为它需要的其他一些类不在类路径上。查找完整的堆栈跟踪,找出 ObjectFactory 缺少哪个类才能正常工作。正如 @mikera 建议的那样,您可以在 Repl 中使用 (import 'org.infoml.jaxb.ObjectFactory) 来执行此操作。 (除非 emacs 吃掉你的堆栈跟踪......)

The way you import the classes is fine. Obviously the ObjectFactory 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 for ObjectFactory to work. As @mikera suggested, you can use (import 'org.infoml.jaxb.ObjectFactory) in the Repl to do that. (Unless emacs eats your stacktrace...)

染墨丶若流云 2024-11-21 07:53:12

我使用以下代码导入 Java 类: 如果

  (ns my.namespace
    (:import [java.io DataInputStream File FileInputStream BufferedInputStream])
    (:import [my.package MyClassOne MyClassTwo])
    ....

相关的 Java 类位于类路径上(如果它们位于 .jar 中就可以了),那么这应该可以工作。

要测试它们是否在类路径上,您还可以在 REPL 中执行以下操作:

  (import 'my.package.MyClassOne)

I use the following code to import Java classes:

  (ns my.namespace
    (:import [java.io DataInputStream File FileInputStream BufferedInputStream])
    (:import [my.package MyClassOne MyClassTwo])
    ....

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:

  (import 'my.package.MyClassOne)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文