You can call a Python method from Java by implementing a Java interface on the python side.
The steps are:
- Create an interface in Java, e.g., py4j.examples.Operator
- In Python, create a class and inside the class, create a Java class with an "implements" field.
- In Python, instantiate a gateway with start_callback_server=True, e.g.,
gateway = JavaGateway(start_callback_server=True) - In Python, instantiate the class implementing a Java interface and send it to the Java side.
- In Java, call the interface.
Example adapted from the Py4J documentation:
Java code:
// File 1
package py4j.examples;
public interface Operator {
public int doOperation(int i, int j);
public int doOperation(int i, int j, int k);
}
// File 2
package py4j.examples;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import py4j.GatewayServer;
public class OperatorExample {
// To prevent integer overflow
private final static int MAX = 1000;
public List<Integer> randomBinaryOperator(Operator op) {
Random random = new Random();
List<Integer> numbers = new ArrayList<Integer>();
numbers.add(random.nextInt(MAX));
numbers.add(random.nextInt(MAX));
numbers.add(op.doOperation(numbers.get(0), numbers.get(1)));
return numbers;
}
}
Python code:
from py4j.java_gateway import JavaGateway
class Addition(object):
def doOperation(self, i, j, k = None):
if k == None:
return i + j
else:
return i + j + k
class Java:
implements = ['py4j.examples.Operator']
if __name__ == '__main__':
gateway = JavaGateway(start_callback_server=True)
operator = Addition()
operator_example = gateway.jvm.py4j.examples.OperatorExample()
# "Sends" python object to the Java side.
numbers = operator_example.randomBinaryOperator(operator)
Answer from Barthelemy on Stack OverflowHow to call java from python using PY4J - Stack Overflow
Both ways, java <=> python, communication using py4j - Stack Overflow
Best way to combine Python and Java?
Error with PySpark and Py4J
Minimal working example:
//AdditionApplication.java
import py4j.GatewayServer;
public class AdditionApplication {
public static void main(String[] args) {
AdditionApplication app = new AdditionApplication();
// app is now the gateway.entry_point
GatewayServer server = new GatewayServer(app);
server.start();
}
}
Compile (make sure that the -cp path to the py4j is valid, otherwise adjust it such that it points to the right place):
javac -cp /usr/local/share/py4j/py4j0.9.jar AdditionApplication.java
Run it:
java -cp .:/usr/local/share/py4j/py4j0.9.jar AdditionApplication
Now, if you run your python script, in the terminal where the java AdditionApplication is running you should see something like:
>>> Hello World!
package test.test;
import py4j.GatewayServer;
public class AdditionApplication {
public int addition(int first, int second) {
return first + second;
}
public static void main(String[] args) {
AdditionApplication app = new AdditionApplication();
// app is now the gateway.entry_point
GatewayServer server = new GatewayServer(app);
server.start();
}
}
create a new class and run it(import py4j0.8.jar at 'py4j-0.8\py4j-0.8\py4j-java' first),then run python program
» pip install py4j
» pip install jtypes.py4j
My project uses some packages that are available only in Python and heavily rely on C libraries. The project also greatly benefits from Java libraries and the JVM. What's the optimal way to call Python functions from Java?
I tried:
-
Small web-services: overhead to serialize data, start and stop the services. Also debugging is harder and implementing each new function is now double the effort.
-
Jpy: a library that runs an interpreter in the JVM. Spare the service start/stop, but: isn't really feasible for more than a single-liner, data translation between Java and Python is cumbersome, and I also encountered runtime segmentation fault errors.
Any other options?
The project is in the machine-learning domain, so involves exchanging large numeric arrays and text. In some cases the execution switches back and forth between the platforms.