Llamar a Java desde Python

123

¿Cuál es la mejor manera de llamar a Java desde Python? (jython y RPC no son una opción para mí).

He oído hablar de JCC: http://pypi.python.org/pypi/JCC/1.9, un generador de código C ++ para llamar a Java desde C ++ / Python Pero esto requiere compilar todas las llamadas posibles; Prefiero otra solución.

Escuché sobre 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() 

Esto se parece a lo que necesito. Sin embargo, la última versión es de enero de 2009 y veo personas que no compilan JPype.

¿JPype es un proyecto muerto?

¿Hay otras alternativas?

Saludos, David

David Portabella
fuente
3
¿Podría explicar por qué cree que Jython y RPC no son una opción para su situación?
Nathan Davis
2
Parece que, mientras tanto, hubo una nueva versión de JPype: 0.5.4.2 el
28/07/2011

Respuestas:

51

Aquí está mi resumen de este problema: 5 formas de llamar a Java desde Python

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

Respuesta corta: Jpype funciona bastante bien y está probado en muchos proyectos (como python-boilerpipe), pero Pyjnius es más rápido y simple que JPype

He intentado Pyjnius / Jnius, JCC, javabridge, Jpype y Py4j.

Py4j es un poco difícil de usar, ya que necesita iniciar una puerta de enlace, agregando otra capa de fragilidad.

Jie Bao
fuente
135

También puedes usar Py4J . Hay un ejemplo en la portada y mucha documentación, pero esencialmente, solo llama a los métodos Java desde su código python como si fueran métodos 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

A diferencia de Jython, una parte de Py4J se ejecuta en la máquina virtual de Python, por lo que siempre está "actualizada" con la última versión de Python y puede usar bibliotecas que no funcionan bien en Jython (por ejemplo, lxml). La otra parte se ejecuta en la máquina virtual Java a la que desea llamar.

La comunicación se realiza a través de sockets en lugar de JNI y Py4J tiene su propio protocolo (para optimizar ciertos casos, administrar la memoria, etc.)

Descargo de responsabilidad: soy el autor de Py4J

Barthelemy
fuente
Gracias por el enlace. parece una alternativa de código abierto a lo que djna propuso, CodeMesh. Definitivamente lo echaré un vistazo. Sin embargo, existe el mismo problema que en CodeMesh, requiere iniciar el proceso de Java antes y asegurarse de que se esté ejecutando antes de usar python (consulte el ejemplo en la página web principal del proyecto, ListPrinter.java -> main -> GatewayServer.start ( )). Este es un posible punto de falla. Sigo pensando que el enfoque de JPype es excelente; solo que parece un proyecto muerto.
David Portabella
8
@alvas Sigo manteniendo Py4J si eso es lo que querías decir.
Barthelemy
@Barthelemy, ¿cómo hacer para integrar si el código Java depende de una biblioteca, opencv en mi caso?
1
@stack solo asegúrese de agregar opencv en su classpath y podrá acceder a él desde Python cuando inicie GatewayServer.
Barthelemy
¿Esto funciona para cualquier paquete? Intenté: s = gateway.jvm.ch.ethz.ssh2.crypto.Base64() bt_out = s.decode();aquí la clase Base64 tiene el método encode () y decode () y es parte del paquete ch.ethz.ssh2.cryptoen mi archivo .jar. Obtengofrom py4j.reflection import MethodInvoker ImportError: No module named reflection
Vishal Sahu
19

Pyjnius

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

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

Desde la página de github:

Un módulo de Python para acceder a las clases de Java como clases de Python usando JNI.

PyJNIus es un "trabajo en progreso".

Vista rápida

>>> 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
gdw2
fuente
5

Estoy en OSX 10.10.2 y logré usar JPype.

Encontré problemas de instalación con Jnius ( otros también lo han hecho ), Javabridge instaló pero cometió errores misteriosos cuando traté de usarlo, PyJ4 tiene este inconveniente de tener que iniciar un servidor Gateway en Java primero, JCC no se instalaría. Finalmente, JPype terminó trabajando. Hay una bifurcación mantenida de JPype en Github. Tiene las principales ventajas de que (a) se instala correctamente y (b) puede convertir muy eficientemente las matrices java en matrices numpy (np_arr = java_arr[:] )

El proceso de instalación fue:

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

Y deberías poder import jpype

La siguiente demostración funcionó:

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

Cuando intenté llamar a mi propio código Java, primero tuve que compilar ( javac ./blah/HelloWorldJPype.java), y tuve que cambiar la ruta JVM de la predeterminada (de lo contrario, obtendré errores inexplicables de "clase no encontrada"). Para mí, esto significaba cambiar el comando startJVM a:

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
...
Peter
fuente
Aquí hay un pequeño módulo contenedor para hacer que JPype sea un poco más fácil de usar: github.com/petered/spiking-mlp/blob/master/spiking_mlp/…
Peter
4

Si estás en Python 3, hay una bifurcación de JPype llamada JPype1-py3

pip install JPype1-py3

Esto funciona para mí en OSX / Python 3.4.3. (Puede que necesite export JAVA_HOME=/Library/Java/JavaVirtualMachines/your-java-version)

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

Últimamente he estado integrando muchas cosas en Python, incluido Java. El método más robusto que he encontrado es usar IKVM y un contenedor C #.

IKVM tiene una pequeña aplicación ordenada que le permite tomar cualquier JAR de Java y convertirlo directamente a .Net DLL. Simplemente traduce el bytecode de JVM a CLR bytecode. Ver http://sourceforge.net/p/ikvm/wiki/Ikvmc/ para más detalles.

La biblioteca convertida se comporta como una biblioteca nativa de C #, y puede usarla sin necesidad de JVM. A continuación, puede crear un proyecto de contenedor de DLL C # y agregar una referencia a la DLL convertida.

Ahora puede crear algunos apéndices de envoltura que llaman a los métodos que desea exponer y marcar esos métodos como DllEport. Ver https://stackoverflow.com/a/29854281/1977538 para más detalles.

La DLL de contenedor actúa como una biblioteca C nativa, con los métodos exportados como los métodos C exportados. Puede conectarse a ellos utilizando ctype como de costumbre.

Lo probé con Python 2.7, pero también debería funcionar con 3.0. Funciona en Windows y Linux.

Si utiliza C #, este es probablemente el mejor enfoque para intentar integrar casi cualquier cosa en Python.

Rob Deary
fuente
1
Uhg ... me perdiste en C #. No votaré en contra, ya que esta es una posibilidad viable para algunos casos, pero esto definitivamente asume Windows y muchas otras cosas.
Jared
2

Estoy empezando a usar JPype 0.5.4.2 (julio de 2011) y parece que funciona bien ...
Estoy en Xubuntu 10.04

Joril
fuente
1

Supongo que si puede pasar de C ++ a Java, ya está todo listo. He visto que un producto del tipo que mencionas funciona bien. Resulta que el que usamos fue CodeMesh . No estoy respaldando específicamente a este proveedor, ni estoy haciendo ninguna declaración sobre la calidad relativa de su producto, pero lo he visto funcionar en un escenario de gran volumen.

En general, diría que, si es posible, recomendaría mantenerse alejado de la integración directa a través de JNI si puede. Algún enfoque de servicio REST simple o arquitectura basada en colas tenderá a ser más simple de desarrollar y diagnosticar. Puede obtener un rendimiento bastante decente si utiliza estas tecnologías desacopladas con cuidado.

djna
fuente
RPC (o REST) ​​no es una opción para mí.
David Portabella
Esto requeriría iniciar el proceso Java antes y asegurarse de que se esté ejecutando antes de usar python. Este es un posible punto de falla. El enfoque de JPype es excelente; solo que parece un proyecto muerto.
David Portabella
Estoy dando consejos generales. JNI es un campo minado potencial.
djna
0

A través de mi propia experiencia tratando de ejecutar algún código Java desde Python, de manera similar a cómo se ejecuta el código Python dentro del código Java en Python, no pude encontrar una metodología sencilla.

Mi solución a mi problema fue ejecutar este código java como scripts de beanshell llamando al intérprete de beanshell como un comando de shell desde mi código python después de editar el código java en un archivo temporal con los paquetes y variables apropiados.

Si de lo que estoy hablando es útil de alguna manera, me complace ayudarlo a compartir más detalles de mis soluciones.

sombra alaa
fuente