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

时间:2011-06-07 00:38:00

标签: java clojure compilation noclassdeffounderror

我已经被困了好几天了,我知道我曾经去过一次。我可能错过了一些明显的东西。任何帮助将不胜感激。

在我的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时(通过C-c C-k或(load-file "src/infwb/cardmaker.clj"),我得到以下异常:

Could not initialize class org.infoml.jaxb.ObjectFactory
  [Thrown class java.lang.NoClassDefFoundError]

我已经离开了我的机器,试图消除无意中的问题作为问题的根源。我在互联网上研究了几件事 - 没有运气。我查看了MANIFEST.MF文件的线索,并将jar文件剥离到我需要的类。我现在已经两次睡了一晚 - 仍然没有解决方案。

使用Clojure中的现有Java类是一件有用的事情。我很感激任何人都可以给我的帮助。感谢。


ADDENDUM:我的问题是由许多因素造成的,包括丢失的jar文件。 @ kotarak的回答很明显。感谢。

3 个答案:

答案 0 :(得分:2)

我并非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 interop访问它们。这是一个例子

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

要运行此程序,您有许多不同的选项。请参阅leiningen docs。看起来您正在使用emacs,请参阅swank clojure。以这种方式使用leiningen应该可以解决类路径问题。

答案 1 :(得分:1)

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

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

这应该可以提供相关的Java类在类路径上(如果它们在.jar中就没问题)。

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

  (import 'my.package.MyClassOne)

答案 2 :(得分:1)

import课程的方式很好。显然,ObjectFactory类无法初始化,因为它需要的其他类不在类路径上。查看完整的堆栈跟踪,找出ObjectFactory缺少哪个类。正如@mikera建议的那样,你可以在Repl中使用(import 'org.infoml.jaxb.ObjectFactory)来做到这一点。 (除非emacs吃掉你的堆栈跟踪...)