Samudra Ganguly
Samudra Ganguly

Reputation: 844

Custom input to a Python program from a Java program

I am trying to make a full-fledged Java program that runs a python program. The python program is as follows:

print('Enter two numbers')
a = int(input())
b = int(input())
c = a + b
print(c)

If I execute this code, the terminal looks something like this:

Enter two numbers
5
3
8

Now, I want the same output when executing this code from Java. Here is my Java code:

import java.io.*;
class RunPython {
    public static void main(String[] args) throws IOException {
        String program = "print('Enter two numbers')\na = int(input())\nb = int(input())\nc = a + b\nprint(a)\nprint(b)\nprint(c)";
        FileWriter fileWriter = new FileWriter("testjava.py");
        BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
        bufferedWriter.write(program);
        bufferedWriter.close();
        Process process = Runtime.getRuntime().exec("python testjava.py");
        InputStreamReader inputStreamReader = new InputStreamReader(process.getInputStream());
        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(process.getOutputStream());
        InputStreamReader read = new InputStreamReader(System.in);
        BufferedReader in = new BufferedReader(read);
        String output;
        while (process.isAlive()) {
            while (!bufferedReader.ready());
            System.out.println(bufferedReader.ready());
            while (!(output = bufferedReader.readLine()).isEmpty()) {
                System.out.println(output);
            }
            bufferedReader.close();
            if (process.isAlive()) {
                outputStreamWriter.write(in.readLine());
            }
        }
    }
}

But while running this program, only the first line is displayed and the first input is taken. After that, the program does not respond. What mistake am I making? And what is the solution?

Upvotes: 3

Views: 791

Answers (2)

Anders Lindgren
Anders Lindgren

Reputation: 378

Dealing with Input and Output to another process is a bit messy and you can read a good answer to how you could do it here

So applying those answers to your code could be something like this:

import java.io.*;
import java.util.Scanner;

class RunPython {
    public static void main(String[] args) throws IOException {
//        String program = "print('Enter two numbers')\na = int(input())\nprint(a)\nb = int(input())\nprint(b)\nc = a + b\nprint(c)";
        // If you are using Java 15 or newer you can write code blocks
        String program = """
                print('Enter first number')
                a = int(input())
                print(a)
                print('Enter second number')
                b = int(input())
                print(b)
                c = a + b
                print(c)
                """;
        FileWriter fileWriter = new FileWriter("testjava.py");
        BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
        bufferedWriter.write(program);
        bufferedWriter.close();

        Process process =
                new ProcessBuilder("python", "testjava.py")
                        .redirectErrorStream(true)
                        .start();

        Scanner scan = new Scanner(System.in);

        BufferedReader pythonOutput = new BufferedReader(new InputStreamReader(process.getInputStream()));
        BufferedWriter pythonInput = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));

        Thread thread = new Thread(() -> {
            String input;
            while (process.isAlive() && (input = scan.nextLine()) != null) {
                try {
                    pythonInput.write(input);
                    pythonInput.newLine();
                    pythonInput.flush();
                } catch (IOException e) {
                    System.out.println(e.getLocalizedMessage());
                    process.destroy();
                    System.out.println("Python program terminated.");
                }
            }
        });
        thread.start();

        String output;
        while (process.isAlive() && (output = pythonOutput.readLine()) != null) {
            System.out.println(output);
        }
        pythonOutput.close();
        pythonInput.close();
    }
}

Note that the pythonInput is a BufferedWriter in Java and vice versa the pythonOutput is a BufferedReader.

Upvotes: 3

Eno Gerguri
Eno Gerguri

Reputation: 677

Using Process:

Process p = new ProcessBuilder(
    "python", "myScript.py", "firstargument Custom input to a Python program from a Java program"
).start();

You can add as many arguments as you want when running it.


Using Jython (Easier option):

//Java code implementing Jython and calling your python_script.py
import org.python.util.PythonInterpreter;
import org.python.core.*;

public class ImportExample {
   public static void main(String [] args) throws PyException
   {
       PythonInterpreter pi = new PythonInterpreter();
       pi.execfile("path_to_script\\main.py");
       pi.exec("Any custom input from this java program in python to be run");
   }
}

Which embeds the Jython and can be read about here.

Note: you may have to initialize your interpreter with your python.path if you want to use any packages you have installed. You can do this by adding the following code above the code already given:

Properties properties = System.getProperties();
properties.put("python.path", ".\\src\\test\\resources");  // example of path to custom modules (you change this to where the custom modules you would want to import are)
PythonInterpreter.initialize(System.getProperties(), properties, new String[0]);

You can also return values if you need to go the other way round which can be found in the Jython documentation

Upvotes: 1

Related Questions