从Python调用Java

问题:从Python调用Java

从python调用Java的最佳方法是什么?(jython和RPC对我来说不是一个选择)。

我听说过JCC:http : //pypi.python.org/pypi/JCC/1.9 一个用于从C ++ / Python调用Java的C ++代码生成器,但这需要编译所有可能的调用。我希望有另一个解决方案。

我听说过JPype:http : //jpype.sourceforge.net/ 教程:http : //www.slideshare.net/onyame/mixing-python-and-java

import jpype 
jpype.startJVM(path to jvm.dll, "-ea") 
javaPackage = jpype.JPackage("JavaPackageName") 
javaClass = javaPackage.JavaClassName 
javaObject = javaClass() 
javaObject.JavaMethodName() 
jpype.shutdownJVM() 

这看起来像我需要的。但是,最新版本是2009年1月,我看到人们无法编译JPype。

JPype是一个死项目吗?

还有其他选择吗?

问候,大卫

What is the best way to call java from python? (jython and RPC are not an option for me).

I’ve heard of JCC: http://pypi.python.org/pypi/JCC/1.9 a C++ code generator for calling Java from C++/Python But this requires compiling every possible call; I would prefer another solution.

I’ve hear about JPype: http://jpype.sourceforge.net/ tutorial: http://www.slideshare.net/onyame/mixing-python-and-java

import jpype 
jpype.startJVM(path to jvm.dll, "-ea") 
javaPackage = jpype.JPackage("JavaPackageName") 
javaClass = javaPackage.JavaClassName 
javaObject = javaClass() 
javaObject.JavaMethodName() 
jpype.shutdownJVM() 

This looks like what I need. However, the last release is from Jan 2009 and I see people failing to compile JPype.

Is JPype a dead project?

Are there any other alternatives?

Regards, David


回答 0

这是我对这个问题的总结:从Python调用Java的5种方法

http://baojie.org/blog/2014/06/16/call-java-from-python/(已缓存

简短的答案:Jpype效果很好,并且在许多项目中都得到了证明(例如python-boilerpipe),但是Pyjnius比JPype更快,更简单。

我已经尝试过Pyjnius / Jnius,JCC,javabridge,Jpype和Py4j。

Py4j有点难以使用,因为您需要启动网关,从而增加了另一层脆弱性。

Here is my summary of this problem: 5 Ways of Calling Java from Python

http://baojie.org/blog/2014/06/16/call-java-from-python/ (cached)

Short answer: Jpype works pretty well and is proven in many projects (such as python-boilerpipe), but Pyjnius is faster and simpler than JPype

I have tried Pyjnius/Jnius, JCC, javabridge, Jpype and Py4j.

Py4j is a bit hard to use, as you need to start a gateway, adding another layer of fragility.


回答 1

您也可以使用Py4J。头版上有一个示例和大量文档,但是从本质上讲,您只是从python代码中调用Java方法,就像它们是python方法一样:

from py4j.java_gateway import JavaGateway
gateway = JavaGateway()                        # connect to the JVM
java_object = gateway.jvm.mypackage.MyClass()  # invoke constructor
other_object = java_object.doThat()
other_object.doThis(1,'abc')
gateway.jvm.java.lang.System.out.println('Hello World!') # call a static method

与Jython相反,Py4J的一部分在Python VM中运行,因此它始终与最新版本的Python“保持最新”,并且您可以使用在Jython上运行不佳的库(例如lxml)。另一部分在您要调用的Java VM中运行。

通信是通过套接字而不是通过JNI进行的,并且Py4J具有自己的协议(用于优化某些情况,管理内存等)。

免责声明:我是Py4J的作者

You could also use Py4J. There is an example on the frontpage and lots of documentation, but essentially, you just call Java methods from your python code as if they were python methods:

from py4j.java_gateway import JavaGateway
gateway = JavaGateway()                        # connect to the JVM
java_object = gateway.jvm.mypackage.MyClass()  # invoke constructor
other_object = java_object.doThat()
other_object.doThis(1,'abc')
gateway.jvm.java.lang.System.out.println('Hello World!') # call a static method

As opposed to Jython, one part of Py4J runs in the Python VM so it is always “up to date” with the latest version of Python and you can use libraries that do not run well on Jython (e.g., lxml). The other part runs in the Java VM you want to call.

The communication is done through sockets instead of JNI and Py4J has its own protocol (to optimize certain cases, to manage memory, etc.)

Disclaimer: I am the author of Py4J


回答 2

皮尤尼斯

文件:http : //pyjnius.readthedocs.org/en/latest/

GitHub:https : //github.com/kivy/pyjnius

从github页面:

使用JNI将Java类作为Python类访问的Python模块。

PyJNIus是“进行中的工作”。

快速概述

>>> from jnius import autoclass
>>> autoclass('java.lang.System').out.println('Hello world') Hello world

>>> Stack = autoclass('java.util.Stack')
>>> stack = Stack()
>>> stack.push('hello')
>>> stack.push('world')
>>> print stack.pop() world
>>> print stack.pop() hello

Pyjnius.

Docs: http://pyjnius.readthedocs.org/en/latest/

Github: https://github.com/kivy/pyjnius

From the github page:

A Python module to access Java classes as Python classes using JNI.

PyJNIus is a “Work In Progress”.

Quick overview

>>> from jnius import autoclass
>>> autoclass('java.lang.System').out.println('Hello world') Hello world

>>> Stack = autoclass('java.util.Stack')
>>> stack = Stack()
>>> stack.push('hello')
>>> stack.push('world')
>>> print stack.pop() world
>>> print stack.pop() hello

回答 3

我使用OSX 10.10.2,并成功使用JPype。

遇到Jnius的安装问题(其他人也有),安装了Javabridge,但是在我尝试使用它时出现了神秘的错误,PyJ4的不便之处在于必须首先在Java中启动Gateway服务器,而JCC无法安装。最终,JPype结束了工作。在Github上有一个JPype维护分支。它的主要优点是(a)正确安装,并且(b)可以非常有效地将java数组转换为numpy array(np_arr = java_arr[:]

安装过程为:

git clone https://github.com/originell/jpype.git
cd jpype
python setup.py install

而且您应该能够 import jpype

以下演示有效:

import jpype as jp
jp.startJVM(jp.getDefaultJVMPath(), "-ea")
jp.java.lang.System.out.println("hello world")
jp.shutdownJVM() 

当我尝试调用自己的Java代码时,必须先进行编译(javac ./blah/HelloWorldJPype.java),并且必须将JVM路径从默认值更改(否则,将出现无法解释的“找不到类”错误)。对我来说,这意味着将startJVM命令更改为:

jp.startJVM('/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/MacOS/libjli.dylib', "-ea")
c = jp.JClass('blah.HelloWorldJPype')  
# Where my java class file is in ./blah/HelloWorldJPype.class
...

I’m on OSX 10.10.2, and succeeded in using JPype.

Ran into installation problems with Jnius (others have too), Javabridge installed but gave mysterious errors when I tried to use it, PyJ4 has this inconvenience of having to start a Gateway server in Java first, JCC wouldn’t install. Finally, JPype ended up working. There’s a maintained fork of JPype on Github. It has the major advantages that (a) it installs properly and (b) it can very efficiently convert java arrays to numpy array (np_arr = java_arr[:])

The installation process was:

git clone https://github.com/originell/jpype.git
cd jpype
python setup.py install

And you should be able to import jpype

The following demo worked:

import jpype as jp
jp.startJVM(jp.getDefaultJVMPath(), "-ea")
jp.java.lang.System.out.println("hello world")
jp.shutdownJVM() 

When I tried calling my own java code, I had to first compile (javac ./blah/HelloWorldJPype.java), and I had to change the JVM path from the default (otherwise you’ll get inexplicable “class not found” errors). For me, this meant changing the startJVM command to:

jp.startJVM('/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/MacOS/libjli.dylib', "-ea")
c = jp.JClass('blah.HelloWorldJPype')  
# Where my java class file is in ./blah/HelloWorldJPype.class
...

回答 4

如果您使用的是Python 3,则有一个JPype的分支,称为JPype1-py3

pip install JPype1-py3

这对我适用于OSX / Python 3.4.3。(您可能需要export JAVA_HOME=/Library/Java/JavaVirtualMachines/your-java-version

from jpype import *
startJVM(getDefaultJVMPath(), "-ea")
java.lang.System.out.println("hello world")
shutdownJVM()

If you’re in Python 3, there’s a fork of JPype called JPype1-py3

pip install JPype1-py3

This works for me on OSX / Python 3.4.3. (You may need to export JAVA_HOME=/Library/Java/JavaVirtualMachines/your-java-version)

from jpype import *
startJVM(getDefaultJVMPath(), "-ea")
java.lang.System.out.println("hello world")
shutdownJVM()

回答 5

最近,我一直在将很多东西集成到Python中,包括Java。我发现的最可靠的方法是使用IKVM和C#包装器。

IKVM有一个简洁的小应用程序,它允许您使用任何Java JAR,并将其直接转换为.Net DLL。它只是将JVM字节码转换为CLR字节码。有关详细信息,请参见http://sourceforge.net/p/ikvm/wiki/Ikvmc/

转换后的库的行为就像本机C#库一样,您可以使用它而无需JVM。然后,您可以创建一个C#DLL包装器项目,并添加对转换后的DLL的引用。

现在,您可以创建一些包装程序存根,以调用要公开的方法,并将这些方法标记为DllEport。有关详细信息,请参见https://stackoverflow.com/a/29854281/1977538

包装DLL的行为就像本机C库一样,导出的方法看起来像导出的C方法。您可以照常使用ctype连接到它们。

我已经在Python 2.7上进行过尝试,但是它也应该在3.0上也可以使用。在Windows和Linuxes上均可使用

如果您碰巧使用C#,那么这可能是将几乎所有内容都集成到python中的最佳方法。

I’ve been integrating a lot of stuff into Python lately, including Java. The most robust method I’ve found is to use IKVM and a C# wrapper.

IKVM has a neat little application that allows you to take any Java JAR, and convert it directly to .Net DLL. It simply translates the JVM bytecode to CLR bytecode. See http://sourceforge.net/p/ikvm/wiki/Ikvmc/ for details.

The converted library behaves just like a native C# library, and you can use it without needing the JVM. You can then create a C# DLL wrapper project, and add a reference to the converted DLL.

You can now create some wrapper stubs that call the methods that you want to expose, and mark those methods as DllEport. See https://stackoverflow.com/a/29854281/1977538 for details.

The wrapper DLL acts just like a native C library, with the exported methods looking just like exported C methods. You can connect to them using ctype as usual.

I’ve tried it with Python 2.7, but it should work with 3.0 as well. Works on Windows and the Linuxes

If you happen to use C#, then this is probably the best approach to try when integrating almost anything into python.


回答 6

我刚刚开始使用JPype 0.5.4.2(2011年7月),并且看起来工作得很好…
我使用的是Xubuntu 10.04

I’m just beginning to use JPype 0.5.4.2 (july 2011) and it looks like it’s working nicely…
I’m on Xubuntu 10.04


回答 7

我假设,如果您可以从C ++到Java,那么您已经准备就绪。我看过您提到的那种产品效果很好。碰巧我们使用的是CodeMesh。我没有特别认可该供应商,也没有对他们的产品相对质量发表任何声明,但是我看到它在相当大的情况下有效。

我通常会说,如果可能的话,我建议您尽量避免通过JNI直接集成。一些简单的REST服务方法或基于队列的体系结构将更易于开发和诊断。如果仔细使用这样的去耦技术,您将获得相当不错的性能。

I’m assuming that if you can get from C++ to Java then you are all set. I’ve seen a product of the kind you mention work well. As it happens the one we used was CodeMesh. I’m not specifically endorsing this vendor, or making any statement about their product’s relative quality, but I have seen it work in quite a high volume scenario.

I would say generally that if at all possible I would recommend keeping away from direct integration via JNI if you can. Some simple REST service approach, or queue-based architecture will tend to be simpler to develop and diagnose. You can get quite decent perfomance if you use such decoupled technologies carefully.


回答 8

根据我自己的经验,尝试从python ia中运行某些Java代码的方式类似于在python中的Java代码中运行python代码的方式,我无法找到一种简单的方法。

我对问题的解决方案是通过在具有适当包和变量的临时文件中编辑Java代码后,通过从python代码中将beanshell解释程序作为shell commnad调用,将此Java代码作为beanshell脚本运行。

如果我在说什么对您有任何帮助,很高兴能帮助您分享我的解决方案的更多详细信息。

Through my own experience trying to run some java code from within python i a manner similar to how python code runs within java code in python, I was unable to a find a straight forward methodology.

My solution to my problem was by running this java code as beanshell scripts by calling the beanshell interpreter as a shell commnad from within my python code after editing the java code in a temporary file with the appropriate packages and variables.

If what I am talking about is helpful in any manner, I am glad to help you sharing more details of my solutions.