LoginSignup
28
26

More than 5 years have passed since last update.

CPythonからJavaのクラスを呼び出す(Py4J)

Last updated at Posted at 2013-06-23

PythonからJavaのライブラリを呼び出して使う方法には以下のようなものがあります。

Jython

インタプリタ自体がJavaで実装されているので、Pythonスクリプトの中で
Javaのクラスや標準ライブラリがそのまま使えます。
一番手っ取り早いですが、CPythonとの互換性が問題になります。
(CPythonの標準ライブラリが一部対応していないなど)

Jythonでjarファイルを呼び出す方法についてはこちら
http://qiita.com/mojaie/items/9add34871a43c4181af7

JPype

CとJavaを連携するJNIを介して、PythonからJavaクラスを呼び出します。
CPythonからJavaをスムーズに呼び出せますが、インストール作業が非常に面倒です。
(Cコンパイラなど依存モジュールの相性によってはインストールすら出来ないことも)

Py4J

Javaの仮想マシン上でサーバを起動し、ソケット通信でCPythonとJavaを連携します。
上述の方法に比べると動作が遅いですが、JavaとPythonが完全に独立しているので、
比較的簡単に環境が構築でき、パッケージ化も容易です。

今回は、Py4Jを用いてjarファイルを呼び出す方法を紹介します。

インストール

pip install py4j

python、javaをインストールしてない場合はインストールしてください。
インストールフォルダ(shareフォルダ?)にpy4j0.7.jarというファイルが含まれているので、
適当な場所にコピーしてJavaのCLASSPATHを通しておきます。

Javaサーバプログラムの作成

まず、既存のjavaクラスを呼び出すためのサーバ用クラスを作ります。
下記は、JClassというクラスのgetStringというメソッドを呼び出すための
JClassEntryPointクラスの例です。

JClassEntryPoint.java

import py4j.GatewayServer;

public class JClassEntryPoint {

    private JClass jclass = null;

    public JClassEntryPoint() {
        this.jclass = new JClass();
    }

    public String getString(String str) {
        return jclass.getString();
    }

    public static void main(String[] args) {
        GatewayServer gatewayServer = new GatewayServer(new JClassEntryPoint());
        gatewayServer.start();
    }
}

class JClass {

    private String str = "hogehoge";

    public String getString(String str) {
        return this.str;
    }
}

JClassEntryPoint.javaを実行可能なjarファイルにしておきます。

呼び出し側Pythonスクリプトの作成

まずsubprocessを使って上述のjarファイルを実行します。
サーバが起動し、JavaGatewayを介してJavaのクラスを読み込めるようになります。
また、atexit.register()を使うことで、Pythonスクリプト終了時に
自動的にサーバを終了させることができます。
time.sleep(2)はサーバが起動する前にJavaGatewayがサーバと通信しようとするのを
防ぐための苦肉の策です。もっといい方法があると思います。

jclassclient.py

import atexit
import subprocess
import time
from py4j.java_gateway import JavaGateway


class JClassClient(object):

    def __init__(self):
        self._gateway = None
        self._process = None
        cmd = ["java", "-jar", "/path/to/jarfile/JClassEntryPoint.jar", "JClassEntryPoint"]
        self._process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE)
        print "jvmprocess started: " + str(self._process.pid)
        atexit.register(self._process.kill)
        time.sleep(2)
        self._gateway = JavaGateway()

    def getString(self):
        return self._gateway.entry_point.getString()


def main():
    client = JClassClient()
    print client.getString()

if __name__ == "__main__":
    main()
28
26
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
28
26