SoFunction
Updated on 2025-04-14

Summary of several methods of calling Python code in Java

introduction

The Python language has rich system management, data processing, and statistics software packages, so the need to call Python code from Java applications is very common and practical. DataX is an off-line synchronization tool for heterogeneous data sources open source by Alibaba, committed to implementing stable and efficient data synchronization functions between various heterogeneous data sources including relational databases (MySQL, Oracle, etc.), HDFS, Hive, ODPS, HBase, FTP, etc. Datax also calls Python scripts through Java. This article introduces several methods to call Python code from java to maximize the advantages of the two languages.

Java core

Java provides two methods, namely ProcessBuilder API and JSR-223 Scripting Engine.

Using ProcessBuilder

Create a local operating system process through ProcessBuilder to start python and execute Python scripts. The script simply outputs "Hello Python!". Requires that the development environment has python installed and environment variables are set.

@Test
public void givenPythonScript_whenPythonProcessInvoked_thenSuccess() throws Exception {
    ProcessBuilder processBuilder = new ProcessBuilder("python", resolvePythonScriptPath(""));
    (true);

    Process process = ();
    List<String> results = readProcessOutput(());

    assertThat("Results should not be empty", results, is(not(empty())));
    assertThat("Results should contain output of script: ", results, hasItem(containsString("Hello Python!")));

    int exitCode = ();
    assertEquals("No errors should be detected", 0, exitCode);
}

private List<String> readProcessOutput(InputStream inputStream) throws IOException {
    try (BufferedReader output = new BufferedReader(new InputStreamReader(inputStream))) {
        return ()
            .collect(());
    }
}

private String resolvePythonScriptPath(String filename) {
    File file = new File("src/test/resources/" + filename);
    return ();
}

First, start the python command with one parameter, the parameter is the absolute path to the python script. It can be placed in the resources directory of the java project. It should be noted that: redirectErrorStream(true), in order to make the error output stream merge into the standard output stream when an error occurs in the execution script. This setting allows you to read error information from the getInputStream() method of the Process object. If this setting is not available, you need to use two methods to get the stream: getInputStream() and getErrorStream() . () Get the Process object, then read the output stream and verify the result.

Using Java Scripting Engine

Java6 first introduced the JSR-223 specification, defining a set of scripting APIs that provide basic scripting functions. These APIs provide a mechanism for executing scripts and sharing values ​​between Java and scripting languages. The main purpose of this specification is to unify the interaction between Java and dynamic scripting languages ​​that implement JVM. Jython is a Java implementation that runs Python on JVM. Assuming we have Jython on CLASSPATH, the framework automatically discovers that we have the possibility to use the script engine and allows us to request the Python script engine directly. Because Maven has Jython, we can reference it in maven, and of course download it and install it directly:

<dependency>
    <groupId></groupId>
    <artifactId>jython</artifactId>
    <version>2.7.2</version>
</dependency>

All supported script engines can be listed through the following code:

public static void listEngines() {
    ScriptEngineManager manager = new ScriptEngineManager();
    List<ScriptEngineFactory> engines = ();

    for (ScriptEngineFactory engine : engines) {
        ("Engine name: {}", ());
        ("Version: {}", ());
        ("Language: {}", ());

        ("Short Names:");
        for (String names : ()) {
            (names);
        }
    }
}

If Jython is available in the environment, you should see the corresponding output:

...
Engine name: jython
Version: 2.7.2
Language: python
Short Names:
python
jython

Now call the script using Jython:

@Test
public void givenPythonScriptEngineIsAvailable_whenScriptInvoked_thenOutputDisplayed() throws Exception {
    StringWriter writer = new StringWriter();
    ScriptContext context = new SimpleScriptContext();
    (writer);

    ScriptEngineManager manager = new ScriptEngineManager();
    ScriptEngine engine = ("python");
    (new FileReader(resolvePythonScriptPath("")), context);
    assertEquals("Should contain script output: ", "Hello Python!", ().trim());
}

Using this API is simpler than the example above. First, set the ScriptContext to include a StringWriter, which is used to save the output of the execution script. Then provide the abbreviation to let ScriptEngineManager look for script engines, which can be used with python or jython. Finally verify that the output is consistent with the expected one.

In fact, you can also use the Python Interpretor class to directly call the embedded python code:

@Test
public void givenPythonInterpreter_whenPrintExecuted_thenOutputDisplayed() {
    try (PythonInterpreter pyInterp = new PythonInterpreter()) {
        StringWriter output = new StringWriter();
        (output);

        ("print('Hello Python!')");
        assertEquals("Should contain script output: ", "Hello Python!", ().trim());
    }
}

Using the Python Interpreter class, you can directly execute python code through the exec method. As in the previous example, the execution output is captured through StringWriter. Let's see another example:

@Test
public void givenPythonInterpreter_whenNumbersAdded_thenOutputDisplayed() {
    try (PythonInterpreter pyInterp = new PythonInterpreter()) {
        ("x = 10+10");
        PyObject x = ("x");
        assertEquals("x: ", 20, ());
    }
}

The above example can use the get method to access variable values. The following example shows how to catch errors:

try (PythonInterpreter pyInterp = new PythonInterpreter()) {
    ("import syds");
}

Running the above code will throw a PyException exception, just like executing a Python script locally output error.
Here are a few things to note:

  • PythonIntepreter implements AutoCloseable, which is best used with try-with-resources.
  • The Python Intepreter class name is not a parser that represents Python code. Python programs run in Jython in jvm and need to be compiled into java bytecode before execution.
  • Although Jython is a Python implementation of Java, it may not contain all the same subpackages as native Python.

The following example shows how to assign java variables to Python variables:

import ; 
import .*; 
 
class test3{
    public static void main(String a[]){

        int number1 = 10;
        int number2 = 32;
    
        try (PythonInterpreter pyInterp = new PythonInterpreter()) {
            ("number1", new PyInteger(number1));
            ("number2", new PyInteger(number2));

            ("number3 = number1+number2");
            PyObject number3 = ("number3");

            ("val : "+());
        }
    }
}

Summarize

This article describes how to call Python scripts from Java, using the jython script engine is simpler than the ProcessBuilder class. In addition, Python can easily build http applications, and Java can also directly call HTTP services through the HTTP protocol to achieve interaction.

This is the end of this article about several methods of calling Python code in Java. For more related Java calling Python code, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!