Sebagian besar hit google teratas untuk "memanggil clojure dari java" sudah usang dan merekomendasikan clojure.lang.RT
untuk menggunakan kompilasi kode sumber. Bisakah Anda membantu dengan penjelasan yang jelas tentang bagaimana memanggil Clojure dari Jawa dengan anggapan Anda telah membangun toples dari proyek Clojure dan memasukkannya ke dalam classpath?
java
clojure
clojure-java-interop
Arthur Ulfeldt
sumber
sumber
Jawaban:
Pembaruan : Karena jawaban ini diposting, beberapa alat yang tersedia telah berubah. Setelah jawaban asli, ada pembaruan termasuk informasi tentang cara membangun contoh dengan alat saat ini.
Ini tidak sesederhana mengkompilasi ke stoples dan memanggil metode internal. Tampaknya ada beberapa trik untuk membuat semuanya bekerja. Berikut adalah contoh file Clojure sederhana yang dapat dikompilasi ke stoples:
Jika Anda menjalankannya, Anda akan melihat sesuatu seperti:
Dan inilah program Java yang memanggil
-binomial
fungsi dalamtiny.jar
.Outputnya adalah:
Bagian pertama sihir menggunakan
:methods
kata kunci dalamgen-class
pernyataan. Tampaknya diperlukan untuk membiarkan Anda mengakses sesuatu fungsi Clojure seperti metode statis di Jawa.Hal kedua adalah membuat fungsi wrapper yang bisa dipanggil oleh Java. Perhatikan bahwa versi kedua
-binomial
memiliki tanda hubung di depannya.Dan tentu saja toples Clojure sendiri harus berada di jalur kelas. Contoh ini menggunakan stoples Clojure-1.1.0.
Pembaruan : Jawaban ini telah diuji ulang menggunakan alat berikut:
Bagian Clojure
Pertama buat proyek dan struktur direktori terkait menggunakan Leiningen:
Sekarang, ubah ke direktori proyek.
Dalam direktori proyek, buka
project.clj
file dan edit sedemikian rupa sehingga isinya seperti yang ditunjukkan di bawah ini.Sekarang, pastikan semua dependensi (Clojure) tersedia.
Anda mungkin melihat pesan tentang mengunduh botol Clojure pada saat ini.
Sekarang edit file Clojure
C:\projects\com.domain.tiny\src\com\domain\tiny.clj
sedemikian rupa sehingga berisi program Clojure yang ditunjukkan dalam jawaban asli. (File ini dibuat ketika Leiningen menciptakan proyek.)Banyak keajaiban di sini adalah dalam deklarasi namespace. The
:gen-class
memberitahu sistem untuk membuat sebuah kelas bernamacom.domain.tiny
dengan metode statis tunggal yang disebutbinomial
, fungsi mengambil dua argumen integer dan mengembalikan ganda. Ada dua fungsi yang sama bernamabinomial
, fungsi Clojure tradisional, dan-binomial
dan pembungkus dapat diakses dari Jawa. Perhatikan tanda hubung dalam nama fungsi-binomial
. Awalan default adalah tanda hubung, tetapi dapat diubah ke sesuatu yang lain jika diinginkan. The-main
Fungsi hanya membuat beberapa panggilan ke fungsi binomial untuk memastikan bahwa kita mendapatkan hasil yang benar. Untuk melakukan itu, kompilasi kelas dan jalankan program.Anda akan melihat output yang ditunjukkan pada jawaban asli.
Sekarang bungkus dalam wadah dan taruh di tempat yang nyaman. Salin toples Clojure di sana juga.
Bagian Jawa
Leiningen memiliki tugas bawaan
lein-javac
,, yang seharusnya dapat membantu kompilasi Java. Sayangnya, tampaknya rusak di versi 2.1.3. Itu tidak dapat menemukan JDK yang diinstal dan tidak dapat menemukan repositori Maven. Jalur untuk keduanya telah menyematkan ruang pada sistem saya. Saya berasumsi bahwa itulah masalahnya. Setiap IDE Java dapat menangani kompilasi dan pengemasan juga. Tetapi untuk posting ini, kita akan menjadi sekolah tua dan melakukannya di baris perintah.Pertama buat file
Main.java
dengan konten yang ditunjukkan dalam jawaban asli.Untuk mengkompilasi bagian java
Sekarang buat file dengan beberapa informasi meta untuk ditambahkan ke toples yang ingin kita buat. Di
Manifest.txt
, tambahkan teks berikutSekarang kemas semuanya ke dalam satu file jar besar, termasuk program Clojure kami dan stoples Clojure.
Untuk menjalankan program:
Output dasarnya identik dengan yang diproduksi oleh Clojure saja, tetapi hasilnya telah dikonversi menjadi Java double.
Seperti yang disebutkan, Java IDE mungkin akan menangani argumen kompilasi yang berantakan dan pengemasannya.
sumber
Pada Clojure 1.6.0, ada cara baru yang disukai untuk memuat dan menjalankan fungsi Clojure. Metode ini sekarang lebih disukai daripada memanggil RT secara langsung (dan menggantikan banyak jawaban lain di sini). Javadoc ada di sini - titik masuk utama adalah
clojure.java.api.Clojure
.Untuk mencari dan memanggil fungsi Clojure:
Fungsi dalam
clojure.core
dimuat secara otomatis. Ruang nama lain dapat dimuat melalui persyaratan:IFn
s dapat diteruskan ke fungsi dengan urutan yang lebih tinggi, misalnya contoh di bawah ini diteruskanplus
keread
:Sebagian besar
IFn
di Clojure merujuk ke fungsi. Namun, beberapa merujuk pada nilai data yang tidak berfungsi. Untuk mengakses ini, gunakanderef
sebagai gantifn
:Kadang-kadang (jika menggunakan beberapa bagian lain dari runtime Clojure), Anda mungkin perlu memastikan bahwa runtime Clojure diinisialisasi dengan benar - memanggil metode pada kelas Clojure sudah cukup untuk tujuan ini. Jika Anda tidak perlu memanggil metode pada Clojure, maka cukup menyebabkan kelas memuat cukup (di masa lalu telah ada rekomendasi serupa untuk memuat kelas RT; ini sekarang lebih disukai):
sumber
Clojure.read("'(1 2 3")
. Akan masuk akal untuk mengajukan ini sebagai permintaan penyempurnaan meskipun untuk memberikan Clojure.quote () atau dengan membuatnya berfungsi sebagai var.'(1 2 3)
Anda menulis sesuatu sepertiClojure.var("clojure.core", "list").invoke(1,2,3)
. Dan jawabannya sudah memiliki contoh cara menggunakanrequire
: itu hanya var seperti yang lain.EDIT Jawaban ini ditulis pada tahun 2010, dan berfungsi pada saat itu. Lihat jawaban Alex Miller untuk solusi yang lebih modern.
Kode apa yang ditelepon dari Jawa? Jika Anda memiliki kelas yang dihasilkan dengan gen-class, cukup panggil saja. Jika Anda ingin memanggil fungsi dari skrip, lihat contoh berikut .
Jika Anda ingin mengevaluasi kode dari string, di dalam Java, maka Anda dapat menggunakan kode berikut:
sumber
RT.var("namespace", "my-var").deref()
.RT.load("clojure/core");
di awal. Apa kelakuannya yang aneh?EDIT: Saya menulis jawaban ini hampir tiga tahun yang lalu. Di Clojure 1.6 ada API yang tepat persis untuk tujuan memanggil Clojure dari Jawa. Harap jawaban Alex Miller untuk informasi terbaru.
Jawaban asli dari 2011:
Seperti yang saya lihat, cara paling sederhana (jika Anda tidak menghasilkan kelas dengan kompilasi AOT) adalah dengan menggunakan clojure.lang.RT untuk mengakses fungsi-fungsi di clojure. Dengan itu Anda dapat meniru apa yang akan Anda lakukan di Clojure (tidak perlu mengkompilasi dengan cara khusus):
Dan di Jawa:
Ini sedikit lebih verbose di Jawa, tapi saya harap jelas bahwa potongan-potongan kode setara.
Ini harus berfungsi selama Clojure dan file sumber (atau file yang dikompilasi) dari kode Clojure Anda ada di classpath.
sumber
Saya setuju dengan jawaban clartaq, tetapi saya merasa bahwa pemula juga dapat menggunakan:
Jadi saya membahas semua itu di posting blog ini .
Kode Clojure terlihat seperti ini:
Setup proyek leiningen 1.7.1 terlihat seperti ini:
Kode Java terlihat seperti ini:
Atau Anda juga bisa mendapatkan semua kode dari proyek ini di github .
sumber
Ini bekerja dengan Clojure 1.5.0:
sumber
Jika use case adalah untuk memasukkan JAR yang dibangun dengan Clojure dalam aplikasi Java, saya menemukan memiliki namespace terpisah untuk antarmuka antara dua dunia yang bermanfaat:
Namespace inti dapat menggunakan contoh yang disuntikkan untuk menyelesaikan tugasnya:
Untuk tujuan pengujian, antarmuka dapat dihapus:
sumber
Teknik lain yang berfungsi juga dengan bahasa lain di atas JVM adalah mendeklarasikan antarmuka untuk fungsi yang ingin Anda panggil dan kemudian menggunakan fungsi 'proxy' untuk membuat instance yang mengimplementasikannya.
sumber
Anda juga dapat menggunakan kompilasi AOT untuk membuat file kelas yang mewakili kode clojure Anda. Baca dokumentasi tentang kompilasi, kelas-gen, dan teman-teman di dokumen Clojure API untuk detail tentang cara melakukan ini, tetapi pada dasarnya Anda akan membuat kelas yang memanggil fungsi clojure untuk setiap pemanggilan metode.
Alternatif lain adalah dengan menggunakan defprotocol baru dan fungsionalitas deftype, yang juga akan memerlukan kompilasi AOT tetapi memberikan kinerja yang lebih baik. Saya belum tahu detail bagaimana melakukan ini, tetapi sebuah pertanyaan di milis mungkin akan berhasil.
sumber