JCCを試してみる
JCC は、 Javaのライブラリを Python から呼び出すため拡張モジュールを生成してくれるツールで、全文検索ライブラリ Apache Lucene の Python インターフェースである PyLucene 用に開発された。しかし決して PyLucene 専用のツールではなく、Python から Javaを呼び出す必要がある場合に利用できる汎用的なツールである。
とりあえず使ってみる
まずこんな感じの Java クラスを定義してみた。
package hellojcc; import java.io.*; public class HelloJCC { public String msg; public HelloJCC(String s) { msg = s; } public void sayHello() { System.out.println(msg); } }
これを hellojccパッケージに格納し、hellojcc.jar を作成しておく。で、jcc で次のようにしてラッパを作成する。
python -m jcc.__main__ --jar hellojcc.jar # hellojcc.jar からラッパを作成してね --package java.lang # java.lang.* のラッパも作ってね --python pyhellojcc # ラッパモジュールの名前は pyhellojcc にしてね --version 0.0.1 # ラッパモジュールのバージョンは 0.0.1だからね --build # あ、ビルドしといてね --install # ついでにインストールもお願いね
distutilsかsetuptoolsがインストールされていれば、Jarファイルからラッパを作り、インストールまで済ませてくれるお利口さんツールである。これを Pythonから呼び出してみよう。
import pyhellojcc pyhellojcc.initVM() shello = pyhellojcc.HelloJCC("test") shello.sayHello()
簡単だ。jccで生成したモジュールを利用するスレッドでは、使い始める前にかならず pyhellojcc.initVM() を呼び出さなければならないので注意。
pyhellojccにはどんなオブジェクトが定義されているのだろうか? dir(pyhellojcc)としてみると、こんな結果が返ってくる。
['AbstractStringBuilder', 'Appendable', 'Boolean', 'CLASSPATH', 'CharSequence', 'Class', 'ClassLoader', 'ClassNotFoundException', 'Comparable', 'ConstVariableDescriptor', 'Double', 'Enumeration', 'Exception', 'FinalizerClass', 'FinalizerProxy', 'HelloJCC', 'IllegalAccessException', 'IllegalArgumentException', 'InstantiationException', 'Integer', 'InterruptedException', 'InvalidArgsError', 'Iterator', 'JArray', 'JArray_bool', 'JArray_byte', 'JArray_char', 'JArray_double', 'JArray_float', 'JArray_int', 'JArray_long', 'JArray_object', 'JArray_short', 'JArray_string', 'JCCEnv', 'JObject', 'JavaError', 'Long', 'Number', 'NumberFormatException', 'Object', 'Package', 'PrintWriter', 'RuntimeException', 'SecurityException', 'StackTraceElement', 'String', 'StringBuffer', 'StringBuilder', 'StringWriter', 'Throwable', 'VERSION', 'Writer', '__builtins__', '__dir__', '__doc__', '__file__', '__name__', '__package__', '__path__', '_pyhellojcc', 'findClass', 'getVMEnv', 'initVM', 'os']
HelloJCC の他に、jccのオプションで指定した java.lang 以下のクラスもちゃんと使えるようになっている。
オーバーロードは?
Javaのメンバがオーバーロードされている場合はどうなるのだろうか? HelloJCCクラスをこんな感じに書き換えてみる。
public class HelloJCC { public HelloJCC(String s) { System.out.println(s); } public HelloJCC(Integer i) { System.out.println(i); } }
もう一度 pyhellojcc を作成して実験してみると:
c:\src\test>python Python 2.6.2 (r262:71600, Oct 9 2009, 00:10:55) [MSC v.1500 32 bit (Intel)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> import pyhellojcc >>> pyhellojcc.initVM() <jcc.JCCEnv object at 0x01A4B150> >>> h = pyhellojcc.HelloJCC(u"あいうえお") あいうえお >>> h = pyhellojcc.HelloJCC(100) Traceback (most recent call last): File "<stdin>", line 1, in <module> pyhellojcc.InvalidArgsError: (<type 'HelloJCC'>, '__init__', (100,)) >>> n = pyhellojcc.Integer(100) >>> h = pyhellojcc.HelloJCC(n) 100
数値->java.lang.Integer の自動変換はやってくれないみたいだけど、自分で Integer() のインスタンスを作成すれば正しくオーバーロードも解決してくれた。
もう少し複雑な例
もう一つクラスを定義する。
package hellojcc; public class HelloArg { String arg; public HelloArg() { } public void setArg(String s) { arg = s; } public String getArg() { return arg; } }
HelloJCC もこんな感じにしてみる。
public class HelloJCC { public String msg; public Integer imsg; public HelloArg arg; public HelloJCC(String s) { msg = s; } public HelloJCC(Integer i) { imsg = i; } public HelloJCC(HelloArg a) { arg = a; } public void sayHello() { System.out.println(getObj()); } public Object getObj() { if (msg != null) { return msg; } else if (imsg != null) { return imsg; } else if (arg != null) { return arg; } throw new RuntimeException("No arg!"); } }
するとこんな感じで実行することができる
>>> shello = pyhellojcc.HelloJCC("test") >>> shello.sayHello() test >>> ihello = pyhellojcc.HelloJCC(pyhellojcc.Integer(123)) >>> ihello.sayHello() 123 >>> a = pyhellojcc.HelloArg() >>> a.setArg("abcdefg") >>> ahello = pyhellojcc.HelloJCC(a) >>> ahello.sayHello() hellojcc.HelloArg@e0e1c6
HelloJCC.getObj()で、Object型が返ってきたらどうなるのだろうか?
>>> print ahello.getObj() hellojcc.HelloArg@e0e1c6 >>> print ahello.getObj().getArg() Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'Object' object has no attribute 'getArg'
自動的には HelloArg 型への変換をしてくれないみたいだ。Java のクラスには cast_() というメソッドが定義されていて、これを使えば目的の型に変換できるようになっている。
>>> arg = ahello.getObj() >>> type(arg) <type 'Object'> >>> arg2 = pyhellojcc.HelloArg.cast_(arg) >>> type(arg2) <type 'HelloArg'> >>>