2010-09-06 32 views
83

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

He oído hablar de CCM: http://pypi.python.org/pypi/JCC/1.9 un generador de código C++ para llamar a Java desde C++/Python Pero esto requiere la compilación de todas las posibles llamada; Yo preferiría otra solución.

He oyen acerca 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, el último lanzamiento es de enero de 2009 y veo personas que no compilan JPype.

¿JPype es un proyecto muerto?

¿Hay alguna otra alternativa?

Saludos, David

+3

¿Podría explicar por qué cree que Jython y RPC no son una opción para su situación? –

+1

Parece que, mientras tanto, había una nueva versión de JPype: 0.5.4.2 el 2011-07-28 – Joril

Respuesta

26

Aquí está mi resumen de este problema: 5 maneras 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 se ha demostrado en muchos proyectos (como python-boilerpipe), pero Pyjnius es más rápido y más sencillo que JPype

He tratado Pyjnius/Jnius, CCM, 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.

+2

Tu enlace está roto. Por favor actualice para obtener puntos. – Robino

1

Asumo que si se puede obtener de C++ para Java, entonces está todo listo. He visto un producto del tipo que mencionas que funciona bien. Como sucede, el que usamos era CodeMesh. No estoy respaldando específicamente a este proveedor ni 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 le recomendaría que se mantenga alejado de la integración directa a través de JNI si puede. Algún enfoque simple de servicio REST o arquitectura basada en colas tenderá a ser más simple de desarrollar y diagnosticar. Puede obtener un rendimiento bastante decente si utiliza dichas tecnologías desacopladas con cuidado.

+0

RPC (o REST) ​​no es una opción para mí. –

+0

Esto requeriría iniciar el proceso de Java antes, y asegúrese 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. –

+0

Estoy dando consejos generales. JNI es un campo de minas potencial. – djna

0

A través de mi propia experiencia tratando de ejecutar algunos códigos java desde dentro de python de manera similar a cómo funciona el código python dentro del código java en python, no pude encontrar una metodología directa.

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

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

106

También podría usar Py4J. Hay un ejemplo en la página principal y un montón de documentación, pero en esencia, que acaba de llamar a métodos Java desde el 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 segundo Python VM por lo que siempre está "actualizado" con la última versión de Python y puede usar bibliotecas que no se ejecutan 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, para la gestión de memoria, etc.)

responsabilidad: yo soy el autor de Py4J

+0

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 ejecuta 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. –

+0

¿La solución todavía funciona hoy? – alvas

+5

@alvas Todavía mantengo Py4J si eso es lo que quieres decir. – Barthelemy

2

Estoy comenzando a usar JPype 0.5.4.2 (julio de 2011) y parece que está funcionando bien ...
Estoy en Xubuntu 10.04

11

Pyjnius.

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

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

Desde la página de GitHub:

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 
1

Si estás en Python 3, hay un tenedor de JPype llama JPype1-py3

pip install JPype1-py3 

Esto funciona para mí en OSX/Python 3.4.3. (Es posible 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() 
2

he estado integrando una gran cantidad de cosas en Python últimamente, incluyendo 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 Java JAR y convertirlo directamente a .Net DLL. Simplemente traduce el bytecode de JVM a bytecode de CLR. Vea http://sourceforge.net/p/ikvm/wiki/Ikvmc/ para más detalles.

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

Ahora puede crear algunos talones de envoltura que llaman a los métodos que desea exponer, y marcar esos métodos como DllEport. Vea 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 que se parecen a los métodos exportados de C. Puede conectarse a ellos usando ctype como de costumbre.

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

Si usa C#, este es probablemente el mejor método para intentar integrar casi cualquier cosa en python.

3

Estoy en OSX 10.10.2 y logré usar JPype.

Tuve problemas de instalación con Jnius (others have too), instalé Javabridge pero cometí misteriosos errores cuando traté de usarlo, PyJ4 tiene este inconveniente de tener que iniciar primero un servidor Gateway en Java, JCC no se instaló.Finalmente, JPype terminó trabajando. Hay un maintained fork of JPype en Github. Tiene las ventajas principales que (a) se instala correctamente y (b) se puede convertir de manera muy eficiente matrices de Java a numpy matriz (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 usted debe ser capaz a import jpype

La siguiente demostración trabajado:

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, tuve que primero co mpile (javac ./blah/HelloWorldJPype.java), y tuve que cambiar la ruta JVM del valor predeterminado (de lo contrario, obtendría inexplicables errores 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 
... 
+0

Un pequeño módulo contenedor para hacer que JPype sea un poco más fácil de usar está aquí: https://github.com/petered/spiking-mlp/blob/master/spiking_mlp/jpype_connect.py – Peter