1. ホーム
  2. java

[解決済み] javaからclojureを呼び出す

2022-04-23 14:02:15

質問

Googleで検索すると、quot;calling clojure from java"のトップヒットのほとんどは古く、次のものを使うことを推奨しています。 clojure.lang.RT を使用してソースコードをコンパイルしてください。Clojureプロジェクトからjarをビルドし、クラスパスに含めたと仮定して、JavaからClojureを呼び出す方法について明確な説明で助けていただけませんか?

解決方法は?

更新情報 : この回答が投稿された後、利用できるツールの一部が変更されました。元の回答の後、現在のツールでサンプルを構築する方法に関する情報を含む更新があります。

jarにコンパイルして、内部のメソッドを呼び出すというような単純なものではありません。しかし、すべてをうまく動かすには、いくつかのコツがあるようです。jarにコンパイルできる簡単なClojureファイルの例です。

(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)))
)

実行すると、次のように表示されるはずです。

(binomial 5 3): 10
(binomial 10042 111): 49068389575068144946633777...

そして、以下はその -binomial 関数を 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));
    }
}

出力されるのは

(binomial 5 3): 10.0
(binomial 10042, 111): 4.9068389575068143E263

最初のマジックは :methods キーワードを gen-class ステートメントを使用します。これは、Javaの静的メソッドのようにClojure関数にアクセスできるようにするために必要なようです。

2つ目は、Javaから呼び出せるラッパー関数を作ることです。第二のバージョンは -binomial は、前にダッシュを付けています。

そしてもちろん、Clojureのjar自体がクラスのパス上になければなりません。この例ではClojure-1.1.0 jarを使用しています。

更新情報 : この回答は、以下のツールを使用して再テストされました。

  • Clojure 1.5.1
  • ライニンゲン 2.1.3
  • JDK 1.7.0 Update 25

Clojureの部分

まず、Leiningenを使用してプロジェクトと関連するディレクトリ構造を作成します。

C:\projects>lein new com.domain.tiny

ここで、プロジェクトディレクトリに変更します。

C:\projects>cd com.domain.tiny

プロジェクトディレクトリで project.clj ファイルを編集し、以下のような内容にしてください。

(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)

ここで、すべての依存関係(Clojure)が利用可能であることを確認します。

C:\projects\com.domain.tiny>lein deps

この時点でClojure jarのダウンロードに関するメッセージが表示されるかもしれません。

Clojure ファイルを編集します。 C:\projects\com.domain.tiny\src\com\domain\tiny.clj 元の答えにあるClojureプログラムを含むようにします。(このファイルはライニンゲンがプロジェクトを作成したときに作成されたものです。)

ここでのマジックの多くは、名前空間宣言にある。この宣言は :gen-class という名前のクラスを作成するようにシステムに指示します。 com.domain.tiny という静的メソッドを1つ持ち binomial この関数は、2つの整数の引数を取り、doubleを返す。同じような名前の関数が2つある binomial 従来のClojureの関数である -binomial とJavaからアクセスできるラッパーです。関数名のハイフンに注意 -binomial . デフォルトの接頭辞はハイフンですが、必要に応じて他のものに変更することができます。その場合 -main 関数は、正しい結果を得るために二項関数を何回か呼び出すだけです。そのためには、クラスをコンパイルして、プログラムを実行します。

C:\projects\com.domain.tiny>lein run

元の答えにあるような出力が表示されるはずです。

今度はこれをjarにパッケージして、どこか便利な場所に置いてください。Clojureのjarもそこにコピーしてください。

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.

Javaパート

ライニンゲンにはタスクが組み込まれています。 lein-javac これは、Javaのコンパイルを助けることができるはずです。残念ながら、バージョン2.1.3では壊れているようです。インストールされたJDKが見つからず、Mavenのリポジトリも見つかりません。私のシステムでは、両方へのパスにはスペースが埋め込まれています。私はそれが問題であると仮定します。どんなJava IDEでも、コンパイルとパッケージングを処理することができます。しかし、この記事では、古い学校に行って、コマンドラインでそれを行うことにします。

まず、ファイルを作成します。 Main.java を、元の答えにあるような内容で書いてください。

java部分をコンパイルする場合

javac -g -cp target\com.domain.tiny-0.1.0-SNAPSHOT.jar -d target\src\com\domain\Main.java

ここで、ビルドしたいjarに追加するメタ情報を記述したファイルを作成します。このファイルは Manifest.txt に、以下のテキストを追加します。

Class-Path: lib\com.domain.tiny-0.1.0-SNAPSHOT.jar lib\clojure-1.5.1.jar
Main-Class: Main

さて、ClojureプログラムとClojure jarを含めて、すべてを1つの大きなjarファイルにパッケージングします。

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

プログラムを実行すること。

C:\projects\com.domain.tiny\target>java -jar Interop.jar
(binomial 5 3): 10.0
(binomial 10042, 111): 4.9068389575068143E263

出力はClojureだけで生成されたものと基本的に同じですが、結果はJavaのdoubleに変換されています。

前述したように、面倒なコンパイル引数やパッケージングは、おそらくJava IDEがやってくれるでしょう。