Большинство популярных хитов Google для "вызова clojure из Java" устарели и рекомендуют использовать clojure.lang.RT
для компиляции исходного кода. Не могли бы вы помочь с четким объяснением того, как вызывать Clojure из Java, предполагая, что вы уже создали jar из проекта Clojure и включили его в путь к классам?
java
clojure
clojure-java-interop
Артур Ульфельдт
источник
источник
Ответы:
Обновление : с тех пор, как этот ответ был опубликован, некоторые из доступных инструментов изменились. После первоначального ответа есть обновление, включающее информацию о том, как построить пример с использованием текущих инструментов.
Это не так просто, как компилирование в jar и вызов внутренних методов. Хотя, кажется, есть несколько хитростей, чтобы заставить все это работать. Вот пример простого файла Clojure, который можно скомпилировать в jar:
Если вы запустите его, вы должны увидеть что-то вроде:
А вот Java-программа, которая вызывает
-binomial
функцию вtiny.jar
.Это вывод:
Первая часть волшебства использует
:methods
ключевое слово вgen-class
заявлении. Похоже, что это необходимо для того, чтобы вы могли получить доступ к функции Clojure, что-то вроде статических методов в Java.Второе - создать функцию-оболочку, которая может быть вызвана Java. Обратите внимание, что перед второй версией
-binomial
есть тире.И, конечно, сама банка Clojure должна быть на пути класса. В этом примере использовался jar Clojure-1.1.0.
Обновление : этот ответ был повторно протестирован с использованием следующих инструментов:
Часть Clojure
Сначала создайте проект и связанную структуру каталогов, используя Leiningen:
Теперь перейдите в каталог проекта.
В каталоге проекта откройте
project.clj
файл и отредактируйте его так, чтобы содержимое было таким, как показано ниже.Теперь убедитесь, что все зависимости (Clojure) доступны.
На этом этапе вы можете увидеть сообщение о загрузке банки Clojure.
Теперь отредактируйте файл Clojure так
C:\projects\com.domain.tiny\src\com\domain\tiny.clj
, чтобы он содержал программу Clojure, показанную в исходном ответе. (Этот файл был создан, когда Лейнинген создал проект.)Большая часть волшебства здесь находится в объявлении пространства имен.
:gen-class
Говорит системе , чтобы создать класс с именемcom.domain.tiny
с помощью одного метода статической называетсяbinomial
, функция принимает два целочисленных аргумента и возвращающей в два раза. Есть две функции с одинаковыми именамиbinomial
, традиционная функция Clojure и-binomial
оболочка, доступная из Java. Обратите внимание на дефис в имени функции-binomial
. Префикс по умолчанию - дефис, но при желании его можно изменить на что-то другое.-main
Функция просто делает пару звонков в биномиальной функции , чтобы гарантировать , что мы получаем правильные результаты. Для этого скомпилируйте класс и запустите программу.Вы должны увидеть результат, показанный в оригинальном ответе.
Теперь упакуйте его в банку и положите в удобное место. Скопируйте туда банку Clojure.
Часть Java
Лейнинген имеет встроенную задачу,
lein-javac
которая должна помочь с компиляцией Java. К сожалению, в версии 2.1.3 он не работает. Он не может найти установленный JDK и не может найти репозиторий Maven. Пути к обоим имеют встроенные пробелы в моей системе. Я предполагаю, что это проблема. Любая Java IDE также может обрабатывать компиляцию и упаковку. Но для этого поста мы идем в старую школу и делаем это в командной строке.Сначала создайте файл
Main.java
с содержимым, показанным в исходном ответе.Для компиляции Java-части
Теперь создайте файл с некоторой мета-информацией для добавления в банку, которую мы хотим построить. В
Manifest.txt
, добавьте следующий текстТеперь упакуйте все это в один большой файл jar, включая нашу программу Clojure и jar Clojure.
Чтобы запустить программу:
Вывод практически идентичен выводу только Clojure, но результат был преобразован в Java double.
Как уже упоминалось, Java IDE, вероятно, позаботится о беспорядочных аргументах компиляции и упаковке.
источник
Начиная с Clojure 1.6.0, появился новый предпочтительный способ загрузки и вызова функций Clojure. Этот метод теперь предпочтительнее прямого вызова RT (и заменяет многие другие ответы здесь). Javadoc здесь - главная точка входа
clojure.java.api.Clojure
.Для поиска и вызова функции Clojure:
Функции в
clojure.core
загружаются автоматически. Другие пространства имен могут быть загружены с помощью require:IFn
s может быть передано в функции более высокого порядка, например, приведенный ниже пример переходитplus
кread
:Большинство
IFn
в Clojure относятся к функциям. Некоторые, однако, относятся к нефункциональным значениям данных. Чтобы получить доступ к ним, используйтеderef
вместоfn
:Иногда (если используется какая-то другая часть среды выполнения Clojure), вам может потребоваться убедиться, что среда выполнения Clojure правильно инициализирована - для этого достаточно вызова метода класса Clojure. Если вам не нужно вызывать метод в Clojure, достаточно просто загрузить класс для загрузки (в прошлом была аналогичная рекомендация по загрузке класса RT; теперь это предпочтительнее):
источник
Clojure.read("'(1 2 3")
. Было бы разумно подать это как запрос на расширение, хотя и предоставить Clojure.quote () или заставить его работать как var.'(1 2 3)
вы пишете что-то вродеClojure.var("clojure.core", "list").invoke(1,2,3)
. И в ответе уже есть пример использованияrequire
: это просто переменная, как и любая другая.РЕДАКТИРОВАТЬ Этот ответ был написан в 2010 году, и работал в то время. Смотрите ответ Алекса Миллера для более современного решения.
Какой код вызывается из Java? Если у вас есть класс, сгенерированный с помощью gen-class, просто вызовите его. Если вы хотите вызвать функцию из скрипта, посмотрите на следующий пример .
Если вы хотите оценить код из строки внутри Java, то вы можете использовать следующий код:
источник
RT.var("namespace", "my-var").deref()
.RT.load("clojure/core");
в начале. Что за странное поведение?РЕДАКТИРОВАТЬ: я написал этот ответ почти три года назад. В Clojure 1.6 существует правильный API именно для вызова Clojure из Java. Пожалуйста , ответ Алекса Миллера для получения актуальной информации.
Оригинальный ответ с 2011 года:
На мой взгляд, самый простой способ (если вы не генерируете класс с компиляцией AOT) - это использовать clojure.lang.RT для доступа к функциям в clojure. С его помощью вы можете имитировать то, что вы сделали бы в Clojure (не нужно специально компилировать вещи):
И на Яве:
Это немного более многословно в Java, но я надеюсь, что ясно, что части кода эквивалентны.
Это должно работать, пока Clojure и исходные файлы (или скомпилированные файлы) вашего кода Clojure находятся в пути к классам.
источник
Я согласен с ответом клартака, но я чувствовал, что новички также могут использовать:
Итак, я рассмотрел все это в этом блоге .
Код Clojure выглядит так:
Настройка проекта leiningen 1.7.1 выглядит следующим образом:
Код Java выглядит следующим образом:
Или вы также можете получить весь код из этого проекта на GitHub .
источник
Это работает с Clojure 1.5.0:
источник
Если сценарий использования должен включать JAR, созданный с помощью Clojure, в приложении Java, я обнаружил, что было бы полезно иметь отдельное пространство имен для интерфейса между двумя мирами:
Базовое пространство имен может использовать внедренный экземпляр для выполнения своих задач:
Для целей тестирования интерфейс может быть заглушен:
источник
Другой метод, который работает также с другими языками поверх JVM, - это объявить интерфейс для функций, которые вы хотите вызвать, а затем использовать функцию «proxy» для создания экземпляра, который их реализует.
источник
Вы также можете использовать компиляцию AOT для создания файлов классов, представляющих ваш код clojure. Прочтите документацию о компиляции, классе gen и друзьях в документации API Clojure для получения подробной информации о том, как это сделать, но по сути вы создадите класс, который вызывает функции clojure для каждого вызова метода.
Другой альтернативой является использование новых функций defprotocol и deftype, которые также потребуют компиляции AOT, но обеспечат более высокую производительность. Я пока не знаю деталей, как это сделать, но вопрос в списке рассылки, вероятно, поможет.
источник