読者です 読者をやめる 読者になる 読者になる

chikuchikugonzalezの雑記帳

趣味とか日記とかメモとか(∩゚д゚)

PythonからJNIを操作するC拡張を作ってみた

なんとなくPythonの拡張を作ってみたくてこの2日間がんばってみた*1Pythonを扱っているはずだけどC++しかやってないな、そういえば。
で、作ったものはpyjvmモジュールと名づけてみた。何をするものかというと、PythonからJavaVM (JNI関数) を呼ぶだけ。しかもJNIメソッド名ほぼそのままで。

このモジュールを使うと、こんな風にJNIを呼び出せます。

#-*- coding: utf-8 -*-
import pyjvm

jvm = pyjvm.JavaVM()
clazz = jvm.findClass("java/lang/Math")
doubleMaxMethod = jvm.getStaticMethod(clazz, "max", "(DD)D")
floatMaxMethod = jvm.getStaticMethod(clazz, "max", "(FF)F")
intMaxMethod = jvm.getStaticMethod(clazz, "max", "(II)I")
longMaxMethod = jvm.getStaticMethod(clazz, "max", "(JJ)J")

print jvm.callStaticDoubleMethod(clazz, doubleMaxMethod, (127.0, -127.0))
print jvm.callStaticFloatMethod(clazz, floatMaxMethod, (127.0, -127.0))
print jvm.callStaticIntMethod(clazz, intMaxMethod, (127, -127))
print jvm.callStaticLongMethod(clazz, longMaxMethod, (127, -127))

systemClass = jvm.findClass("java/lang/System")
currentTimeMethod = jvm.getStaticMethod(systemClass, "currentTimeMillis", "()J")
print jvm.callStaticLongMethod(systemClass, currentTimeMethod, ()), " [ms]"

まんまJNI関数を呼び出すので、異様にめんどう。でも実装は (関数があんまりないので) 楽かもしれない。
最初はstaticメソッドで終わろうかとも思ったけど、オブジェクトの生成とかも出来ないとダメかな、と思って実装した。結果JFrameを表示できるようになりました。
まぁ、こんなコード (なげぇ…)

#-*- coding: utf-8 -*-
import pyjvm

jvm = pyjvm.JavaVM()
clazz = jvm.findClass("javax/swing/JFrame")
constructor = jvm.getMethod(clazz, "<init>", "()V")
titleMethod = jvm.getMethod(clazz, "setTitle", "(Ljava/lang/String;)V")
visibleMethod = jvm.getMethod(clazz, "show", "()V")
closeOperationMethod = jvm.getMethod(clazz, "setDefaultCloseOperation", "(I)V")
sizeMethod = jvm.getMethod(clazz, "setSize", "(II)V")

# ボタン
btnClazz = jvm.findClass("javax/swing/JLabel")
btnConstructor = jvm.getMethod(btnClazz, "<init>", "(Ljava/lang/String;)V")
containerMethod = jvm.getMethod(clazz, "getContentPane", "()Ljava/awt/Container;")
containerClazz = jvm.findClass("java/awt/Container")
containerAddMethod = jvm.getMethod(containerClazz, "add", "(Ljava/awt/Component;)Ljava/awt/Component;")

# 生成
window = jvm.newObject(clazz, constructor, ())

# Btn
btn = jvm.newObject(btnClazz, btnConstructor, ("Test Button",))
container = jvm.callObjectMethod(window, containerMethod, ())
jvm.callObjectMethod(container, containerAddMethod, (btn,))

# Window
jvm.callVoidMethod(window, titleMethod, ("Hello!",))        # 効果なし
jvm.callVoidMethod(window, closeOperationMethod, (2,))  # 謎。(2)だと落ちる
jvm.callVoidMethod(window, sizeMethod, (320, 240))
jvm.callVoidMethod(window, visibleMethod, ())

を実行すると、こうなる。

メモリリークとかはしている可能性大。あとエラー処理はすっ飛ばしたのでJNI呼び出しがおかしくなるとほいほい強制終了する。そんなんでもよければSkyDriveに置いたので試したい方はドゾ。
pyjvm - Python to Java JNI Extension ver0.1

*1:Visual C++ 2010をインストールしたのも影響していると思われ