Appeler Java depuis Python

123

Quelle est la meilleure façon d'appeler java depuis python? (jython et RPC ne sont pas une option pour moi).

J'ai entendu parler de JCC: http://pypi.python.org/pypi/JCC/1.9 un générateur de code C ++ pour appeler Java à partir de C ++ / Python Mais cela nécessite de compiler tous les appels possibles; Je préférerais une autre solution.

J'ai entendu parler de JPype: http://jpype.sourceforge.net/ tutoriel: 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() 

Cela ressemble à ce dont j'ai besoin. Cependant, la dernière version date de janvier 2009 et je vois des gens qui ne parviennent pas à compiler JPype.

JPype est-il un projet mort?

Y a-t-il d'autres alternatives?

Cordialement, David

David Portabella
la source
3
Pourriez-vous expliquer pourquoi vous pensez que Jython et RPC ne sont pas une option pour votre situation?
Nathan Davis le
2
Il semble qu'entre-temps, il y avait une nouvelle version de JPype: 0.5.4.2 le
28/07/2011

Réponses:

51

Voici mon résumé de ce problème: 5 façons d'appeler Java à partir de Python

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

Réponse courte: Jpype fonctionne plutôt bien et a fait ses preuves dans de nombreux projets (tels que python-kettlepipe), mais Pyjnius est plus rapide et plus simple que JPype

J'ai essayé Pyjnius / Jnius, JCC, javabridge, Jpype et Py4j.

Py4j est un peu difficile à utiliser, car vous devez démarrer une passerelle, ajoutant une autre couche de fragilité.

Jie Bao
la source
135

Vous pouvez également utiliser Py4J . Il y a un exemple sur la page d'accueil et beaucoup de documentation, mais essentiellement, vous appelez simplement des méthodes Java à partir de votre code python comme s'il s'agissait de méthodes 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

Contrairement à Jython, une partie de Py4J s'exécute dans la VM Python donc elle est toujours "à jour" avec la dernière version de Python et vous pouvez utiliser des bibliothèques qui ne fonctionnent pas bien sur Jython (par exemple, lxml). L'autre partie s'exécute dans la machine virtuelle Java que vous souhaitez appeler.

La communication se fait via des sockets au lieu de JNI et Py4J a son propre protocole (pour optimiser certains cas, gérer la mémoire, etc.)

Avertissement: je suis l'auteur de Py4J

Barthélemy
la source
Merci pour le lien. cela ressemble à une alternative open-source à ce que djna a proposé, CodeMesh. Je vais définitivement y jeter un œil. Cependant, il y a le même problème que dans CodeMesh, il nécessite de démarrer le processus Java avant, et de s'assurer qu'il est en cours d'exécution avant d'utiliser python (voir l'exemple dans la page Web principale du projet, ListPrinter.java -> main -> GatewayServer.start ( )). C'est un point d'échec possible. Je pense toujours que l'approche de JPype est excellente; seulement qu'il semble un projet mort.
David Portabella
8
@alvas Je maintiens toujours Py4J si c'est ce que vous vouliez dire.
Barthelemy
@Barthelemy, comment s'y prendre pour intégrer si le code Java est dépendant d'une librairie - opencv dans mon cas?
1
@stack assurez-vous simplement d'ajouter opencv dans votre chemin de classe et vous pourrez y accéder depuis Python lorsque vous démarrez le GatewayServer.
Barthelemy
Cela fonctionne-t-il pour n'importe quel package? J'ai essayé: s = gateway.jvm.ch.ethz.ssh2.crypto.Base64() bt_out = s.decode();Ici, la classe Base64 a la méthode encode () et decode () et fait partie du package ch.ethz.ssh2.cryptodans mon fichier .jar. Je reçoisfrom py4j.reflection import MethodInvoker ImportError: No module named reflection
Vishal Sahu
19

Pyjnius.

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

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

Depuis la page github:

Un module Python pour accéder aux classes Java en tant que classes Python à l'aide de JNI.

PyJNIus est un "Work In Progress".

Rapide vue d'ensemble

>>> 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
la source
5

Je suis sous OSX 10.10.2 et j'ai réussi à utiliser JPype.

Ran dans des problèmes d'installation avec Jnius (d' autres ont aussi ), Javabridge installé mais a donné des erreurs mystérieuses lorsque j'ai essayé de l'utiliser, PyJ4 a cet inconvénient d'avoir à démarrer un serveur de passerelle en Java d'abord, JCC ne l'installerait pas. Enfin, JPype a fini par fonctionner. Il existe un fork de JPype maintenu sur Github. Il a les principaux avantages que (a) il s'installe correctement et (b) il peut très efficacement convertir des tableaux java en tableau numpy ( np_arr = java_arr[:])

Le processus d'installation était:

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

Et tu devrais pouvoir import jpype

La démo suivante a fonctionné:

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

Quand j'ai essayé d'appeler mon propre code java, j'ai dû d'abord compiler ( javac ./blah/HelloWorldJPype.java), et j'ai dû changer le chemin JVM par défaut (sinon vous obtiendrez des erreurs inexplicables "class not found"). Pour moi, cela signifiait changer la commande startJVM en:

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
la source
Un petit module wrapper pour rendre JPype un peu plus facile à utiliser est ici: github.com/petered/spiking-mlp/blob/master/spiking_mlp
Peter
4

Si vous êtes dans Python 3, il existe un fork de JPype appelé JPype1-py3

pip install JPype1-py3

Cela fonctionne pour moi sur OSX / Python 3.4.3. (Vous devrez peut-être export JAVA_HOME=/Library/Java/JavaVirtualMachines/your-java-version)

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

J'ai récemment intégré beaucoup de choses dans Python, y compris Java. La méthode la plus robuste que j'ai trouvée consiste à utiliser IKVM et un wrapper C #.

IKVM a une petite application sympa qui vous permet de prendre n'importe quel JAR Java et de le convertir directement en DLL .Net. Il traduit simplement le bytecode JVM en bytecode CLR. Voir http://sourceforge.net/p/ikvm/wiki/Ikvmc/ pour plus de détails.

La bibliothèque convertie se comporte comme une bibliothèque C # native et vous pouvez l'utiliser sans avoir besoin de la JVM. Vous pouvez ensuite créer un projet wrapper DLL C # et ajouter une référence à la DLL convertie.

Vous pouvez maintenant créer des stubs wrapper qui appellent les méthodes que vous souhaitez exposer et marquer ces méthodes comme DllEport. Voir https://stackoverflow.com/a/29854281/1977538 pour plus de détails.

La DLL wrapper agit exactement comme une bibliothèque C native, les méthodes exportées ressemblant aux méthodes C exportées. Vous pouvez vous y connecter en utilisant ctype comme d'habitude.

Je l'ai essayé avec Python 2.7, mais cela devrait également fonctionner avec 3.0. Fonctionne sur Windows et les Linux

Si vous utilisez C #, alors c'est probablement la meilleure approche à essayer lors de l'intégration de presque tout dans python.

Rob Deary
la source
1
Euh ... tu m'as perdu en C #. Je ne voterai pas contre car c'est une possibilité viable dans certains cas, mais cela suppose définitivement Windows et beaucoup d'autres choses.
Jared
2

Je commence tout juste à utiliser JPype 0.5.4.2 (juillet 2011) et il semble que cela fonctionne bien ...
Je suis sur Xubuntu 10.04

Joril
la source
1

Je suppose que si vous pouvez passer de C ++ à Java, vous êtes prêt. J'ai vu un produit du type que vous mentionnez bien fonctionner. En fait, celui que nous avons utilisé était CodeMesh . Je n'approuve pas spécifiquement ce fournisseur, ni ne fais de déclaration sur la qualité relative de son produit, mais je l'ai vu fonctionner dans un scénario à volume assez élevé.

Je dirais généralement que si cela est possible, je recommanderais d'éviter l'intégration directe via JNI si vous le pouvez. Une approche de service REST simple ou une architecture basée sur une file d'attente aura tendance à être plus simple à développer et à diagnostiquer. Vous pouvez obtenir des performances tout à fait décentes si vous utilisez ces technologies découplées avec soin.

djna
la source
RPC (ou REST) ​​n'est pas une option pour moi.
David Portabella
Cela nécessiterait de démarrer le processus Java avant et de s'assurer qu'il est en cours d'exécution avant d'utiliser python. C'est un point d'échec possible. L'approche de JPype est excellente; seulement qu'il semble un projet mort.
David Portabella
Je donne des conseils généraux. JNI est un champ de mines potentiel.
djna
0

Grâce à ma propre expérience en essayant d'exécuter du code java à partir de python d'une manière similaire à la façon dont le code python s'exécute dans le code java en python, je n'ai pas pu trouver une méthodologie simple.

Ma solution à mon problème était d'exécuter ce code java en tant que scripts beanshell en appelant l'interpréteur beanshell en tant que commande shell à partir de mon code python après avoir édité le code java dans un fichier temporaire avec les packages et les variables appropriés.

Si ce dont je parle est utile de quelque manière que ce soit, je suis heureux de vous aider à partager plus de détails sur mes solutions.

ombragé alaa
la source