Как я могу получить доступ к JAR-классам из моей программы Clojure? - PullRequest
4 голосов
/ 07 июня 2011

Я застрял несколько дней над чем-то, что я знаю Я уже однажды работал.Я, наверное, упускаю что-то очевидное.Буду признателен за любую помощь.

В моей программе 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)))

Когда я распечатываю classpath, который видит 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, либо (load-file "src/infwb/cardmaker.clj"), я получаю следующее исключение:

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

Я дошел до того, что перезагрузил мою машину, чтобы попытаться исключить непреднамеренную ошибку как источник проблемы. I 'Я исследовал несколько вещей в Интернете - не повезло. Я посмотрел на файл MANIFEST.MF для подсказок и разобрал файл jar до тех классов, которые мне нужны. Я спал на нем два раза за ночь сейчас - все ещенет решения.

Полезно использовать существующие классы Java из Clojure. Буду признателен за помощь, которую кто-нибудь сможет мне дать. Спасибо.


ADDENDUM: Моя проблема была вызвана рядом факторов, в том числе отсутствиемархивный файл.Ответ @ kotarak был точным.Спасибо.

Ответы [ 3 ]

2 голосов
/ 07 июня 2011

Я не уверен на 100%, что полностью понял ваш вопрос, но если вы просто пытаетесь получить доступ к своим Java-классам из программы Clojure, я бы использовал 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

Теперь вы можете импортировать ваши классы Java в вашу программу Clojure и получать к ним доступ через взаимодействие с Clojure Java. Вот пример

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

Для запуска этой программы у вас есть куча разных опций. См. leiningen документы . Похоже, вы используете emacs, так что смотрите swank clojure . Использование leiningen таким образом должно решить ваши проблемы с classpath.

1 голос
/ 07 июня 2011

То, как вы import классы в порядке. Очевидно, класс ObjectFactory не может быть инициализирован, потому что какой-то другой класс, в котором он нуждается, не находится на пути к классам. Выполните поиск по полной трассировке стека, чтобы узнать, какой класс отсутствует для работы ObjectFactory. Как подсказал @mikera, вы можете использовать (import 'org.infoml.jaxb.ObjectFactory) в Repl для этого. (Если emacs не съест вашу трассировку стека ...)

1 голос
/ 07 июня 2011

Я использую следующий код для импорта классов Java:

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

Это должно работать, если соответствующие классы Java находятся в пути к классам (это нормально, если они находятся в .jar).

Чтобы проверить, есть ли они на пути к классам, вы также можете сделать следующее в REPL:

  (import 'my.package.MyClassOne)
...