Aktualizacja : od czasu opublikowania tej odpowiedzi niektóre z dostępnych narzędzi uległy zmianie. Po oryginalnej odpowiedzi następuje aktualizacja zawierająca informacje o tym, jak zbudować przykład przy użyciu aktualnych narzędzi.
Nie jest to tak proste, jak kompilacja do pliku jar i wywołanie metod wewnętrznych. Wydaje się jednak, że jest kilka sztuczek, które sprawiają, że wszystko działa. Oto przykład prostego pliku Clojure, który można skompilować do pliku jar:
(ns com.domain.tiny
(:gen-class
:name com.domain.tiny
:methods [#^{:static true} [binomial [int int] double]]))
(defn binomial
"Calculate the binomial coefficient."
[n k]
(let [a (inc n)]
(loop [b 1
c 1]
(if (> b k)
c
(recur (inc b) (* (/ (- a b) b) c))))))
(defn -binomial
"A Java-callable wrapper around the 'binomial' function."
[n k]
(binomial n k))
(defn -main []
(println (str "(binomial 5 3): " (binomial 5 3)))
(println (str "(binomial 10042 111): " (binomial 10042 111)))
)
Jeśli go uruchomisz, powinieneś zobaczyć coś takiego:
(binomial 5 3): 10
(binomial 10042 111): 49068389575068144946633777...
A oto program Java, który wywołuje -binomial
funkcję w tiny.jar
.
import com.domain.tiny;
public class Main {
public static void main(String[] args) {
System.out.println("(binomial 5 3): " + tiny.binomial(5, 3));
System.out.println("(binomial 10042, 111): " + tiny.binomial(10042, 111));
}
}
Jego wynik to:
(binomial 5 3): 10.0
(binomial 10042, 111): 4.9068389575068143E263
Pierwsza magia polega na użyciu :methods
słowa kluczowego w gen-class
instrukcji. Wydaje się, że jest to wymagane, aby umożliwić dostęp do funkcji Clojure, podobnej do metod statycznych w Javie.
Drugą rzeczą jest utworzenie funkcji opakowującej, którą może wywołać Java. Zauważ, że druga wersja -binomial
ma przed sobą myślnik.
I oczywiście sam jar Clojure musi znajdować się na ścieżce klas. W tym przykładzie użyto jar Clojure-1.1.0.
Aktualizacja : ta odpowiedź została ponownie przetestowana przy użyciu następujących narzędzi:
- Clojure 1.5.1
- Leiningen 2.1.3
- JDK 1.7.0 aktualizacja 25
Część Clojure
Najpierw utwórz projekt i powiązaną strukturę katalogów za pomocą Leiningen:
C:\projects>lein new com.domain.tiny
Teraz przejdź do katalogu projektu.
C:\projects>cd com.domain.tiny
W katalogu projektu otwórz project.clj
plik i edytuj go tak, aby zawartość była taka, jak pokazano poniżej.
(defproject com.domain.tiny "0.1.0-SNAPSHOT"
:description "An example of stand alone Clojure-Java interop"
:url "http://clarkonium.net/2013/06/java-clojure-interop-an-update/"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.5.1"]]
:aot :all
:main com.domain.tiny)
Teraz upewnij się, że wszystkie zależności (Clojure) są dostępne.
C:\projects\com.domain.tiny>lein deps
W tym momencie może pojawić się komunikat o pobieraniu słoika Clojure.
Teraz edytuj plik Clojure C:\projects\com.domain.tiny\src\com\domain\tiny.clj
tak, aby zawierał program Clojure pokazany w oryginalnej odpowiedzi. (Ten plik został utworzony, gdy Leiningen utworzył projekt).
Duża część magii tkwi w deklaracji przestrzeni nazw. :gen-class
Informuje system, aby utworzyć klasę o nazwie com.domain.tiny
z jednej metody statycznej nazwie binomial
, funkcja biorąc dwa argumenty całkowite i powracający podwójne. Istnieją dwie podobnie nazwane funkcje binomial
, tradycyjna funkcja Clojure -binomial
i opakowanie dostępne z poziomu języka Java. Zwróć uwagę na myślnik w nazwie funkcji -binomial
. Domyślnym przedrostkiem jest myślnik, ale w razie potrzeby można go zmienić na inny. -main
Funkcja po prostu sprawia, że kilka wywołań funkcji dwumianowego, aby zapewnić, że jesteśmy coraz poprawnych wyników. Aby to zrobić, skompiluj klasę i uruchom program.
C:\projects\com.domain.tiny>lein run
Powinieneś zobaczyć wynik pokazany w oryginalnej odpowiedzi.
Teraz zapakuj go do słoika i umieść w dogodnym miejscu. Skopiuj tam również słoik Clojure.
C:\projects\com.domain.tiny>lein jar
Created C:\projects\com.domain.tiny\target\com.domain.tiny-0.1.0-SNAPSHOT.jar
C:\projects\com.domain.tiny>mkdir \target\lib
C:\projects\com.domain.tiny>copy target\com.domain.tiny-0.1.0-SNAPSHOT.jar target\lib\
1 file(s) copied.
C:\projects\com.domain.tiny>copy "C:<path to clojure jar>\clojure-1.5.1.jar" target\lib\
1 file(s) copied.
Część Java
Leiningen ma wbudowane zadanie, lein-javac
które powinno pomóc przy kompilacji Javy. Niestety wydaje się, że w wersji 2.1.3 jest uszkodzony. Nie może znaleźć zainstalowanego JDK i nie może znaleźć repozytorium Maven. Ścieżki do obu mają osadzone spacje w moim systemie. Zakładam, że w tym tkwi problem. Każde środowisko Java IDE również poradzi sobie z kompilacją i pakowaniem. Ale w tym poście idziemy do starej szkoły i robimy to w wierszu poleceń.
Najpierw utwórz plik Main.java
z zawartością przedstawioną w oryginalnej odpowiedzi.
Aby skompilować część java
javac -g -cp target\com.domain.tiny-0.1.0-SNAPSHOT.jar -d target\src\com\domain\Main.java
Teraz utwórz plik z kilkoma metainformacjami, aby dodać je do jar, który chcemy zbudować. W Manifest.txt
, dodaj następujący tekst
Class-Path: lib\com.domain.tiny-0.1.0-SNAPSHOT.jar lib\clojure-1.5.1.jar
Main-Class: Main
Teraz zapakuj to wszystko w jeden duży plik jar, w tym nasz program Clojure i jar Clojure.
C:\projects\com.domain.tiny\target>jar cfm Interop.jar Manifest.txt Main.class lib\com.domain.tiny-0.1.0-SNAPSHOT.jar lib\clojure-1.5.1.jar
Aby uruchomić program:
C:\projects\com.domain.tiny\target>java -jar Interop.jar
(binomial 5 3): 10.0
(binomial 10042, 111): 4.9068389575068143E263
Dane wyjściowe są zasadniczo identyczne z danymi wygenerowanymi przez sam Clojure, ale wynik został przekonwertowany na podwójną Java.
Jak wspomniano, środowisko Java IDE prawdopodobnie zajmie się niechlujnymi argumentami kompilacji i opakowaniem.