これまで、だいぶ目を背けていたのですが、ClojureとJavaを使うにあたり、そろそろClojureでJavaのクラスを作成したり継承したりというのを覚えてみようと思います。
う〜ん、遅いネタですねぇ…。
ま、気にせずいってみましょう。
まずは
Clojureでソースを書きます。サンプルとしては、こんな感じ。
foo.clj
(ns foo (:gen-class :methods [#^{:static true} [bar [String] String] #^{:static true}[fuga [] void] [echo [String] String]])) (defn -main [] (println "Hello World Main Method")) (defn -bar [name] (str "Hello World By " name " !!")) (defn -fuga [] (println "Hello World")) (defn -echo [this param] param)
超適当。パッケージもなし。ちなみに、パッケージを切る場合は
(ns foo.bar)
みたいにして、なおかつfoo/bar.cljみたいな配置にしないとダメみたいですよ。
で、このクラスは以下のようになっています。
Javaのクラスを生成するのは、
(:gen-class
で指示しています。メソッドについては、
:methods [#^{:static true} [bar [String] String] #^{:static true}[fuga [] void] [echo [String] String]]))
で指示。staticメソッドは、メタデータで指示しています。:methodsキーワードの指定方法は、ClojureDocsとかを見ればよいと思いますが
:methods [ [name [param-types] return-type], ...]
という書き方をします。voidの場合は、voidと書けばよいような…。
続いて、メソッドの宣言。
(defn -main [] (println "Hello World Main Method")) (defn -bar [name] (str "Hello World By " name " !!")) (defn -fuga [] (println "Hello World")) (defn -echo [this param] param)
先頭に「-」が付いていますが、これはgen-classリーダマクロのprefixキーワードのデフォルト値が「-」だからです。
また、インスタンスメソッドの場合は第1引数にthisになるものが入ります。Pythonと同じようなもの?
コンパイル
コンパイルを行うには、compile関数を使います。では、やってみましょう。
$ clj Clojure 1.4.0 user=> (compile 'foo) CompilerException java.io.IOException: そのようなファイルやディレクトリはありません, compiling:(foo.clj:1)
コケましたね。これはどういうことかというと…compile関数の説明を読んでみます。
Compiles the namespace named by the symbol lib into a set of
classfiles. The source for the lib must be in a proper
classpath-relative directory. The output files will go into the
directory specified by *compile-path*, and that directory too must
be in the classpath.
というわけで、*compile-path*に対応するディレクトリが必要だよ、と。*compile-path*の値を確認すると
user=> (println *compile-path*) classes nil
なので、1度REPLを抜けてディレクトリを作成します。
$ mkdir classes
再度、トライ。
$ clj Clojure 1.4.0 user=> (compile 'foo) foo
今度は、うまくいきました。結果は、こんな感じ。
$ ls -l classes 合計 28 -rw-rw-r-- 1 xxxxx xxxxx 929 Oct 19 11:14 foo$_bar.class -rw-rw-r-- 1 xxxxx xxxxx 544 Oct 19 11:14 foo$_echo.class -rw-rw-r-- 1 xxxxx xxxxx 822 Oct 19 11:14 foo$_fuga.class -rw-rw-r-- 1 xxxxx xxxxx 834 Oct 19 11:14 foo$_main.class -rw-rw-r-- 1 xxxxx xxxxx 1469 Oct 19 11:14 foo$loading__4784__auto__.class -rw-rw-r-- 1 xxxxx xxxxx 2277 Oct 19 11:14 foo.class -rw-rw-r-- 1 xxxxx xxxxx 3270 Oct 19 11:14 foo__init.class
mainメソッドを持っているので、直接Javaから起動できます。
$ java -cp classes:/usr/local/clojure/clojure.jar foo Hello World Main Method
Javaから呼んでみる
では、作成したfooクラスをJavaから呼び出してみます。
Caller.java
public class Caller { public static void main(String[] args) { System.out.println(foo.bar("Clojure")); foo.fuga(); foo f = new foo(); System.out.println(f.echo("foo")); } }
コンパイルして、実行。
$ javac -d classes -cp classes Caller.java $ java -cp classes:/usr/local/clojure/clojure.jar Caller Hello World By Clojure !! Hello World foo
OKですね!でも、けっこうハマりました…。