Chamando Java a partir de Python


123

Qual é a melhor maneira de chamar java de python? (jython e RPC não são uma opção para mim).

Ouvi falar do JCC: http://pypi.python.org/pypi/JCC/1.9, um gerador de código C ++ para chamar Java a partir de C ++ / Python. Mas isso requer a compilação de todas as chamadas possíveis; Eu preferiria outra solução.

Ouvi falar do 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() 

Parece o que eu preciso. No entanto, o último lançamento é de janeiro de 2009 e vejo pessoas que não conseguem compilar o JPype.

O JPype é um projeto morto?

Há alguma outra alternativa?

Atenciosamente, David


3
Você poderia explicar por que você acha que o Jython e o RPC não são uma opção para a sua situação?
Nathan Davis

2
Parece que, enquanto isso, houve um novo lançamento do JPype: 0.5.4.2 em
28-07-2011

Respostas:


51

Aqui está o meu resumo deste problema: 5 maneiras de chamar Java a partir de Python

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

Resposta curta: O Jpype funciona muito bem e é comprovado em muitos projetos (como python-boilerpipe), mas o Pyjnius é mais rápido e mais simples que o JPype

Eu tentei Pyjnius / Jnius, JCC, javabridge, Jpype e Py4j.

O Py4j é um pouco difícil de usar, pois você precisa iniciar um gateway, adicionando outra camada de fragilidade.


135

Você também pode usar o Py4J . Há um exemplo na página inicial e muita documentação, mas, basicamente, você chama os métodos Java do seu código python como se fossem 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

Ao contrário do Jython, uma parte do Py4J é executada na VM do Python, por isso está sempre "atualizada" com a versão mais recente do Python e você pode usar bibliotecas que não funcionam bem no Jython (por exemplo, lxml). A outra parte é executada na Java VM que você deseja chamar.

A comunicação é feita através de soquetes, em vez de JNI e o Py4J possui seu próprio protocolo (para otimizar certos casos, gerenciar memória, etc.)

Disclaimer: Eu sou o autor de Py4J


Obrigado pelo link. parece uma alternativa de código aberto ao que o djna propôs, CodeMesh. Definitivamente vou dar uma olhada nisso. No entanto, existe o mesmo problema que no CodeMesh, é necessário iniciar o processo Java antes e verificar se ele está sendo executado antes de usar python (consulte o exemplo na página principal do projeto, ListPrinter.java -> main -> GatewayServer.start ( )). Este é um possível ponto de falha. Eu ainda acho que a abordagem do JPype é excelente; só que parece um projeto morto.
David Portabella

8
@ alvas Ainda mantenho o Py4J se é isso que você quis dizer.
Barthelemy

@ Bartelemy, como proceder para integrar se o código Java depende de uma biblioteca - opencv no meu caso?

1
O @stack apenas adicione opencv ao seu caminho de classe e você poderá acessá-lo no Python quando iniciar o GatewayServer.
Barthelemy #

Isso funciona para qualquer pacote? Eu tentei: s = gateway.jvm.ch.ethz.ssh2.crypto.Base64() bt_out = s.decode();Aqui a classe Base64 possui o método encode () e decode () e faz parte do pacote ch.ethz.ssh2.cryptono meu arquivo .jar. Eu recebofrom 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

Na página do github:

Um módulo Python para acessar classes Java como classes Python usando JNI.

PyJNIus é um "trabalho em andamento".

Visão geral 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

5

Estou no OSX 10.10.2 e consegui usar o JPype.

Ocorreu um problema de instalação com o Jnius ( outros também ), o Javabridge instalou, mas cometeu erros misteriosos quando tentei usá-lo, o PyJ4 tem esse inconveniente de ter que iniciar um servidor Gateway em Java primeiro, o JCC não instalaria. Finalmente, o JPype acabou funcionando. Existe uma bifurcação mantida do JPype no Github. Possui as principais vantagens de que (a) é instalado corretamente e (b) pode converter de maneira muito eficiente matrizes java em matrizes numpy (np_arr = java_arr[:] )

O processo de instalação foi:

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

E você deve ser capaz de import jpype

A seguinte demonstração funcionou:

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

Quando tentei chamar meu próprio código java, tive que primeiro compilar ( javac ./blah/HelloWorldJPype.java) e alterar o caminho da JVM do padrão (caso contrário, você obterá erros inexplicáveis ​​de "classe não encontrada"). Para mim, isso significou alterar o comando startJVM para:

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

Um pequeno módulo de wrapper para fazer JPype um pouco mais fácil de usar é aqui: github.com/petered/spiking-mlp/blob/master/spiking_mlp/...
Peter

4

Se você está no Python 3, há um fork do JPype chamado JPype1-py3

pip install JPype1-py3

Isso funciona para mim no OSX / Python 3.4.3. (Você pode precisar export JAVA_HOME=/Library/Java/JavaVirtualMachines/your-java-version)

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

4

Ultimamente, venho integrando muitas coisas no Python, incluindo Java. O método mais robusto que encontrei é usar o IKVM e um wrapper C #.

O IKVM possui um aplicativo pequeno e elegante que permite pegar qualquer Java JAR e convertê-lo diretamente em .Net DLL. Ele simplesmente converte o bytecode da JVM em bytecode do CLR. Consulte http://sourceforge.net/p/ikvm/wiki/Ikvmc/ para obter detalhes.

A biblioteca convertida se comporta como uma biblioteca C # nativa e você pode usá-la sem precisar da JVM. Em seguida, você pode criar um projeto de wrapper C # DLL e adicionar uma referência à DLL convertida.

Agora você pode criar alguns stubs de invólucro que chamam os métodos que você deseja expor e marcar esses métodos como DllEport. Consulte https://stackoverflow.com/a/29854281/1977538 para obter detalhes.

A DLL do wrapper atua como uma biblioteca C nativa, com os métodos exportados parecidos com os métodos C exportados. Você pode se conectar a eles usando o ctype como de costume.

Eu tentei com o Python 2.7, mas deve funcionar com o 3.0 também. Funciona em Windows e Linux

Se você usa C #, provavelmente esta é a melhor abordagem para tentar ao integrar quase tudo ao python.


1
Uhg ... você me perdeu em C #. Não vou diminuir o voto, já que essa é uma possibilidade viável para alguns casos, mas isso definitivamente assume o Windows e muitas outras coisas.
Jared

2

Estou começando a usar o JPype 0.5.4.2 (julho de 2011) e parece que está funcionando bem ...
Estou no Xubuntu 10.04


1

Estou assumindo que, se você pode passar de C ++ para Java, está tudo pronto. Eu já vi um produto do tipo que você mencionou funcionar bem. Por acaso, o que usamos foi o CodeMesh . Não estou endossando especificamente esse fornecedor ou fazendo qualquer declaração sobre a qualidade relativa de seus produtos, mas já o vi funcionar em um cenário de volume bastante alto.

Eu diria que, se possível, eu recomendaria evitar a integração direta via JNI, se puder. Alguma abordagem simples de serviço REST ou arquitetura baseada em fila tenderá a ser mais simples de desenvolver e diagnosticar. Você pode obter um desempenho bastante decente se usar essas tecnologias dissociadas com cuidado.


RPC (ou REST) ​​não é uma opção para mim.
David Portabella

Isso exigiria iniciar o processo Java antes e verifique se ele está sendo executado antes de usar python. Este é um possível ponto de falha. A abordagem do JPype é excelente; só que parece um projeto morto.
David Portabella

Estou dando conselhos gerais. JNI é um campo minado em potencial.
djna

0

Através da minha própria experiência tentando executar algum código java no python, de maneira semelhante a como o código python é executado dentro do código java no python, não consegui encontrar uma metodologia direta.

Minha solução para o meu problema foi executar esse código java como scripts de casca de feijão, chamando o interpretador de casca de feijão como um commnad de shell no meu código python após editar o código java em um arquivo temporário com os pacotes e variáveis ​​apropriados.

Se o que estou falando é útil de alguma maneira, fico feliz em ajudá-lo a compartilhar mais detalhes de minhas soluções.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.