Większość najpopularniejszych haseł Google dotyczących „wywoływania clojure z javy” jest nieaktualna i zaleca się użycie ich clojure.lang.RT
do kompilacji kodu źródłowego. Czy mógłbyś pomóc w jasnym wyjaśnieniu, jak wywołać Clojure z Java, zakładając, że masz już słoik z projektu Clojure i umieściłeś go w ścieżce klas?
java
clojure
clojure-java-interop
Arthur Ulfeldt
źródło
źródło
Odpowiedzi:
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:
Jeśli go uruchomisz, powinieneś zobaczyć coś takiego:
A oto program Java, który wywołuje
-binomial
funkcję wtiny.jar
.Jego wynik to:
Pierwsza magia polega na użyciu
:methods
słowa kluczowego wgen-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:
Część Clojure
Najpierw utwórz projekt i powiązaną strukturę katalogów za pomocą Leiningen:
Teraz przejdź do katalogu projektu.
W katalogu projektu otwórz
project.clj
plik i edytuj go tak, aby zawartość była taka, jak pokazano poniżej.Teraz upewnij się, że wszystkie zależności (Clojure) są dostępne.
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 nazwiecom.domain.tiny
z jednej metody statycznej nazwiebinomial
, funkcja biorąc dwa argumenty całkowite i powracający podwójne. Istnieją dwie podobnie nazwane funkcjebinomial
, 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.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.
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
Teraz utwórz plik z kilkoma metainformacjami, aby dodać je do jar, który chcemy zbudować. W
Manifest.txt
, dodaj następujący tekstTeraz zapakuj to wszystko w jeden duży plik jar, w tym nasz program Clojure i jar Clojure.
Aby uruchomić program:
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.
źródło
Od Clojure 1.6.0 istnieje nowy preferowany sposób ładowania i wywoływania funkcji Clojure. Ta metoda jest teraz preferowana do bezpośredniego wywoływania RT (i zastępuje wiele innych odpowiedzi tutaj). Javadoc jest tutaj - głównym punktem wejścia jest
clojure.java.api.Clojure
.Aby wyszukać i wywołać funkcję Clojure:
Funkcje w programie
clojure.core
są ładowane automatycznie. Inne przestrzenie nazw mogą być ładowane przez require:IFn
s można przekazać do funkcji wyższego rzędu, np. poniższy przykład przechodziplus
doread
:Większość
IFn
znaków w Clojure odnosi się do funkcji. Jednak kilka z nich odnosi się do wartości danych niezwiązanych z funkcją. Aby uzyskać do nich dostęp, użyjderef
zamiastfn
:Czasami (jeśli używasz innej części środowiska uruchomieniowego Clojure), może być konieczne upewnienie się, że środowisko uruchomieniowe Clojure zostało poprawnie zainicjowane - wystarczy do tego celu wywołanie metody z klasy Clojure. Jeśli nie musisz wywoływać metody w Clojure, wystarczy po prostu spowodować załadowanie klasy (w przeszłości było podobne zalecenie, aby załadować klasę RT; teraz jest to preferowane):
źródło
Clojure.read("'(1 2 3")
. Rozsądne byłoby zgłoszenie tego jako prośby o ulepszenie, aby dostarczyć Clojure.quote () lub sprawić, by działał jako var.'(1 2 3)
, napisz coś w styluClojure.var("clojure.core", "list").invoke(1,2,3)
. A odpowiedź zawiera już przykład użyciarequire
: to po prostu var, jak każdy inny.EDYTUJ Ta odpowiedź została napisana w 2010 roku i działała w tamtym czasie. Zobacz odpowiedź Alexa Millera na bardziej nowoczesne rozwiązanie.
Jaki kod wywołuje z Java? Jeśli masz klasę wygenerowaną za pomocą klasy gen, po prostu ją wywołaj. Jeśli chcesz wywołać funkcję ze skryptu, spójrz na następujący przykład .
Jeśli chcesz ocenić kod ze stringów w Javie, możesz użyć następującego kodu:
źródło
RT.var("namespace", "my-var").deref()
.RT.load("clojure/core");
na początku. Co za dziwne zachowanie?EDYCJA: Napisałem tę odpowiedź prawie trzy lata temu. W Clojure 1.6 znajduje się odpowiednie API, które służy do wywoływania Clojure z Javy. Proszę o odpowiedź Alexa Millera, aby uzyskać aktualne informacje.
Oryginalna odpowiedź z 2011 r .:
Jak widzę, najprostszym sposobem (jeśli nie generujesz klasy z kompilacją AOT) jest użycie clojure.lang.RT w celu uzyskania dostępu do funkcji w clojure. Dzięki niemu możesz naśladować to, co zrobiłbyś w Clojure (nie ma potrzeby kompilowania rzeczy w specjalny sposób):
A w Javie:
W Javie jest trochę bardziej rozwlekły, ale mam nadzieję, że jest jasne, że fragmenty kodu są równoważne.
Powinno to działać, o ile Clojure i pliki źródłowe (lub pliki skompilowane) twojego kodu Clojure znajdują się w ścieżce klas.
źródło
Zgadzam się z odpowiedzią clartaq, ale czułem, że początkujący mogą również skorzystać z:
Więc opisałem to wszystko w tym wpisie na blogu .
Kod Clojure wygląda następująco:
Konfiguracja projektu w Leiningen 1.7.1 wygląda następująco:
Kod Java wygląda następująco:
Możesz też pobrać cały kod z tego projektu na github .
źródło
Działa to z Clojure 1.5.0:
źródło
Jeśli przypadkiem użycia jest włączenie JARa zbudowanego za pomocą Clojure w aplikacji Java, zauważyłem, że korzystna jest oddzielna przestrzeń nazw dla interfejsu między dwoma światami:
Podstawowa przestrzeń nazw może używać wstrzykniętej instancji do wykonywania swoich zadań:
Do celów testowych interfejs można zablokować:
źródło
Inną techniką, która działa również z innymi językami poza JVM, jest zadeklarowanie interfejsu dla funkcji, które chcesz wywołać, a następnie użycie funkcji „proxy” w celu utworzenia instancji, która je implementuje.
źródło
Możesz również użyć kompilacji AOT do tworzenia plików klas reprezentujących kod clojure. Przeczytaj dokumentację dotyczącą kompilacji, klasy gen i przyjaciół w dokumentacji Clojure API, aby uzyskać szczegółowe informacje o tym, jak to zrobić, ale w istocie utworzysz klasę, która wywoła funkcje clojure dla każdego wywołania metody.
Inną alternatywą jest użycie nowych funkcji defprotocol i deftype, które również będą wymagały kompilacji AOT, ale zapewni lepszą wydajność. Nie znam jeszcze szczegółów, jak to zrobić, ale pytanie na liście mailingowej prawdopodobnie by załatwiło sprawę.
źródło