呼び出しclojureでjava
-
24-09-2019 - |
質問
最もトップのgoogleヒットのための"呼び出しclojureでjava"は時代遅れでの使用をお勧めし clojure.lang.RT
をコンパイルのソースコード。かくて、いつも時間に追われているが明確に説明されている電話のかけ方ClojureでJavaを想定していま築しjarをClojureプロジェクトが含まれているクラスパス?
解決
更新:この答えが掲載され、一部のツールをご用意しています。後の答えが更新情報を含むに対しても理解しやすいようにとえば現在のツールです。
すなどの作成、瓶の呼び出しの内部。あいうのを少なくすべての作品になってる。以下に例を示しますのClojure可能なファイル作成への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)))
)
までがついているようなもの:
(binomial 5 3): 10
(binomial 10042 111): 49068389575068144946633777...
ここでは、Javaプログラムを呼び出 -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
ます。と思われる必要が利用できるようになClojure機能のようなものstaticメソッドJava.
第二にやるべきことをラッパー機能によって呼び出されJava.この第二版 -binomial
はダッシュでいます。
もちろんのClojure jar自体のクラスパスです。この例では、Clojure-1.1.0jar.
更新:この答えとして、再試験には以下の手順に従います:
- Clojure1.5.1
- Leiningen2.1.3
- JDK1.7.0 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プログラムに独自の答えです。(このファイル作成時Leiningenプロジェクトを作成した.)
多くの魔法ここでは、名前空間宣言です。の :gen-class
このシステムの作成クラス com.domain.tiny
単一のstaticメソッドと呼ばれ binomial
, 機能という二つの整数の引数を返しまいます。あの同じ機能 binomial
, 伝統的なClojure機能 -binomial
とラッパからアクセスJava.注出版者(社)名を入力してくださの関数名 -binomial
.デフォルトの接頭辞であるハイフンが可能であり、これまでのように変更するには何が望まれる。の -main
機能だけで、カップルの二項機能することを確保するためのしくは正しい。これを実行するには、コンパイルのクラスを実行します。
C:\projects\com.domain.tiny>lein run
きな出力は独自の答えです。
現在のパッケージでの瓶に入れて梱便利です。コピーの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部
Leiningenを内蔵してタスク 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
現在のパッケージにもならなjarファイルを含むClojureプログラムのClojure 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。
このようなJava IDEかの汚パ引数のパッケージ。
他のヒント
はClojureの1.6.0のように、負荷へとClojureの関数呼び出し新しい好適な方法があります。この方法は、現在、直接RTを呼び出す(そしてここで他の回答の多くに取って代わる)に好適です。 javadocはこちらここある - メインエントリポイントは Clojureの機能を検索して呼び出すには: のClojureのほとんどの 時々(Clojureのランタイムの他の部分を使用している場合)、あなたはClojureのランタイムが正しく初期化されていることを確認する必要があるかもしれない - Clojureのクラスのメソッドを呼び出すには、この目的のために十分です。あなたはClojureの上のメソッドを呼び出す必要がない場合は、単に負荷にクラスを引き起こしすれば十分である(過去にRTクラスをロードするために同様の勧告があった。これは現在好ましい):clojure.java.api.Clojure
あります。 P>
IFn plus = Clojure.var("clojure.core", "+");
plus.invoke(1, 2);
clojure.core
の関数は自動的にロードされます。他の名前空間が必要と経由してロードすることができます:IFn require = Clojure.var("clojure.core", "require");
require.invoke(Clojure.read("clojure.set"));
IFn
sは、例えば、より高次の関数に渡すことができます以下の例はplus
にread
を渡すIFn map = Clojure.var("clojure.core", "map");
IFn inc = Clojure.var("clojure.core", "inc");
map.invoke(inc, Clojure.read("[1 2 3]"));
IFn
sは、関数を参照してください。いくつかの、しかし、非機能データ値を参照してください。これらにアクセスするには、代わりにderef
の使用fn
ます:IFn printLength = Clojure.var("clojure.core", "*print-length*");
IFn deref = Clojure.var("clojure.core", "deref");
deref.invoke(printLength);
Class.forName("clojure.java.api.Clojure")
編集この答えは、2010年に書かれた、そしてその時に働いていました。より近代的な解決のためにアレックス・ミラーの回答を参照してください。
、Javaからコードのどのような種類を呼んでいますか?あなたはGEN-クラスで生成されたクラスを持っている場合は、単にそれを呼び出します。スクリプトから関数を呼び出したい場合は、たとえばで、次のに見えます。
あなたは、文字列からコードを評価したい場合は、Javaの内部で、その後、あなたは次のコードを使用することができます:
import clojure.lang.RT;
import clojure.lang.Var;
import clojure.lang.Compiler;
import java.io.StringReader;
public class Foo {
public static void main(String[] args) throws Exception {
// Load the Clojure script -- as a side effect this initializes the runtime.
String str = "(ns user) (defn foo [a b] (str a \" \" b))";
//RT.loadResourceScript("foo.clj");
Compiler.load(new StringReader(str));
// Get a reference to the foo function.
Var foo = RT.var("user", "foo");
// Call it!
Object result = foo.invoke("Hi", "there");
System.out.println(result);
}
}
の EDIT:の私はほぼ3年前にこの答えを書きました。 Clojureの1.6では、JavaからのClojureを呼び出すために、正確に適切なAPIがあります。最新の情報をためてくださいアレックス・ミラーの答えでます。
2011年からのオリジナルの答え:の
私はそれを見るようには、最も簡単な方法は、(あなたがAOTコンパイルしてクラスを生成しない場合)のClojureでのアクセス機能にclojure.lang.RTを使用することです。それによってあなたはClojureの中で(特別な方法で物事をコンパイルする必要が)行われないであろうものを模倣することができます:
;; Example usage of the "bar-fn" function from the "foo.ns" namespace from Clojure
(require 'foo.ns)
(foo.ns/bar-fn 1 2 3)
とJavaでます:
// Example usage of the "bar-fn" function from the "foo.ns" namespace from Java
import clojure.lang.RT;
import clojure.lang.Symbol;
...
RT.var("clojure.core", "require").invoke(Symbol.intern("foo.ns"));
RT.var("foo.ns", "bar-fn").invoke(1, 2, 3);
これは、Javaで少し冗長ですが、私はそれがコードの断片が等価であることが明らかに願っています。
このは限りあなたのClojureコードのClojureのソースファイル(またはコンパイルされたファイル)がクラスパス上にあるように動作するはずです。
いclartaqの答えが感じたので初心者にも利用
- ステップ-バイ-ステップについての情報は、実際にはこの走行
- 情報の流Clojure1.3のは、最近のバージョンのleiningen.
- a Clojure jarることも含まれる主な機能なので、ラン または リンクとしての図書館があります。
思われる このブログ.
のClojureコードは以下のようなものです:
(ns ThingOne.core
(:gen-class
:methods [#^{:static true} [foo [int] void]]))
(defn -foo [i] (println "Hello from Clojure. My input was " i))
(defn -main [] (println "Hello from Clojure -main." ))
のleiningen1.7.1プロジェクト設定は以下のようなものです:
(defproject ThingOne "1.0.0-SNAPSHOT"
:description "Hello, Clojure"
:dependencies [[org.clojure/clojure "1.3.0"]]
:aot [ThingOne.core]
:main ThingOne.core)
Javaのコードは以下のようなものです:
import ThingOne.*;
class HelloJava {
public static void main(String[] args) {
System.out.println("Hello from Java!");
core.foo (12345);
}
}
または使用できる必要がありますすべてのコードから このプロジェクトにはgithub.
Clojureの1.5.0でこの作品ます:
public class CljTest {
public static Object evalClj(String a) {
return clojure.lang.Compiler.load(new java.io.StringReader(a));
}
public static void main(String[] args) {
new clojure.lang.RT(); // needed since 1.5.0
System.out.println(evalClj("(+ 1 2)"));
}
}
のユースケースは、JavaアプリケーションでのClojureで構築されたJARを含めることである場合、私は有益であるために、2つの世界の間のインターフェースのための別の名前空間を有する発見した:
(ns example-app.interop
(:require [example-app.core :as core])
;; This example covers two-way communication: the Clojure library
;; relies on the wrapping Java app for some functionality (through
;; an interface that the Clojure library provides and the Java app
;; implements) and the Java app calls the Clojure library to perform
;; work. The latter case is covered by a class provided by the Clojure lib.
;;
;; This namespace should be AOT compiled.
;; The interface that the java app can implement
(gen-interface
:name com.example.WeatherForecast
:methods [[getTemperature [] Double]])
;; The class that the java app instantiates
(gen-class
:name com.example.HighTemperatureMailer
:state state
:init init
;; Dependency injection - take an instance of the previously defined
;; interface as a constructor argument
:constructors {[com.example.WeatherForecast] []}
:methods [[sendMails [] void]])
(defn -init [weather-forecast]
[[] {:weather-forecast weather-forecast}])
;; The actual work is done in the core namespace
(defn -sendMails
[this]
(core/send-mails (.state this)))
コア名前空間がそのタスクを達成するために注入されたインスタンスを使用することができます:
(ns example-app.core)
(defn send-mails
[{:keys [weather-forecast]}]
(let [temp (.getTemperature weather-forecast)] ...))
はテスト目的のために、インタフェースがスタブすることができます。
(example-app.core/send-mails
(reify com.example.WeatherForecast (getTemperature [this] ...)))
その他の技術を使用して、インスタンスを作成するために呼び出し、「プロキシ」関数を使用したい機能のためのインタフェースを宣言することであるimplemenntsそれらを。
また、あなたのClojureコードを表すクラスファイルを作成するために、AOTコンパイルを使用することができます。コンパイルに関するドキュメントを読んで、これを行う方法の詳細については、ClojureのAPIのドキュメントでGEN-クラスや友人、しかし本質的には、各メソッド呼び出しのためにClojureの関数を呼び出すクラスを作成します。
別の方法もAOTコンパイルを必要としますが、より良いパフォーマンスを提供する新しいdefprotocolとのDeftype機能を使用することです。私はまだこれを行う方法の詳細は知らないが、メーリングリストでの質問は、おそらくトリックを行うだろう。