How to call java objects and functions from CPython?

∥☆過路亽.° 提交于 2019-11-28 18:56:49

The easiest thing to do is

  1. Write a trivial CLI for your java "function". (There's no such thing, so I'll assume you actually mean a method function of a Java class.)

    public class ExposeAMethod {
        public static void main( String args[] ) {
             TheClassToExpose  x = new TheClassToExpose();
            x.theFunction();
        }
    }
    
  2. Compile and build an executable JAR file with this as the entry point. Call it ExposeAMethod.jar

  3. Call this from a command created by subprocess.

    import subprocess
    p = subprocess.Popen("java -jar ExposeAMethod.jar", shell=True)
    sts = os.waitpid(p.pid, 0)
    

This is the minimum. And it's really not much. I count 6 lines of java, 3 lines of Python and you're up and running.

If you want to pass arguments to this Java class constructor or method function, you'll have to write a few more lines of code. You have two choices.

  • Read the arguments from stdin, write the results on stdout. This is relatively easy and performs really well.

  • Parse the arguments as command-line options to Java, write the results on stdout. This is slightly harder, but generalizes very nicely. The bonus is that you now have a useful command-line Java program that you can reuse.

Apologies for resurrecting the thread, but I think I have a better answer :-)

You could also use Py4J which has two parts: a library that runs in CPython (or any Python interpreter for that matter) and a library that runs on the Java VM you want to call.

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

The communication is done through sockets instead of JNI.

Disclaimer: I am the author of Py4J

If you don't want to go the write your own JNI/C route.

The other option is to use jpype which for me is always what I use to access Oracle databases becuase installing the oracle c drivers on a PC is a pita. You can do stuff like (from docs):

 from jpype import * 
 startJVM("d:/tools/j2sdk/jre/bin/client/jvm.dll", "-ea") # or path to your jvm
 java.lang.System.out.println("hello world") 
 shutdownJVM()

It hasn't been updated in a while and there isn't much in the way of documentation but it does work reasonably well.

You'll have to create a python C extension that embeds Java - based on something like http://www.javaworld.com/javaworld/jw-05-2001/jw-0511-legacy.html or else you'll have to start java in a separate subprocess.

Look at our project python-javabridge. It's a Python wrapper around the JNI, heavily used by CellProfiler. It offers both low-level access to the JNI and a high-level reflection-based access to Java objects.

Marko

I don't know for Python, but last time I had to call java from C application (NT service) I had to load jvm.dll. Take a look at JNI documentation.

Also, you call always call

os.system("java com.myapp.MyClass") 

if you are not concerned about performance.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!