In java i needed to run a process in this case node and provide user input programmatically. I could read its output like this:
String path = "/Users/tolymbeknurtai/desktop/projects/servlets/src/main/java/server/tester/tests/example.js";
String[] command = {"node", path};
ProcessBuilder processBuilder = new ProcessBuilder(command);
Process process = processBuilder.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
reader.close();
int exitCode = process.waitFor();
System.out.println("process exited with code " + exitCode);
Once i try to access output stream and write something to it i am unable to even read the output of the program. When i run the code i doesn't finish executing. Apparently output stream is unable to write.
try {
String path = "/Users/tolymbeknurtai/desktop/projects/servlets/src/main/java/server/tester/tests/example.js";
String[] command = {"node", path};
ProcessBuilder processBuilder = new ProcessBuilder(command);
Process process = processBuilder.start();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
writer.write("hello");
writer.flush();
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
writer.close();
reader.close();
int exitCode = process.waitFor();
System.out.println("Node.js process exited with code " + exitCode);
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
How can I solve this problem? Found someone using this but in my case it doesn't work. The javascript code in the example.js:
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question('',(input) => {
console.log(input);
rl.close();
});
The problem is that the standard-out and standard-in of the subprocess happen concurrently. If you try to deal with all of the input and then all of the output (or vice versa), it probably will hang, at least some of the time, because the process is stuck waiting for its own output to get processed.
While you could do some of the consumption in other threads, your particular case has an easier solution. Just make the subprocess inherit the standard-out and standard-error of Java process:
ProcessBuilder processBuilder = new ProcessBuilder(command);
processBuilder.redirectOutput(ProcessBuilder.Redirect.INHERIT);
processBuilder.redirectError(ProcessBuilder.Redirect.INHERIT);
Process process = processBuilder.start();
try (BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(
process.getOutputStream()))) {
writer.write("hello");
}
The use of INHERIT will cause the subprocess to send all of its standard-otuput to the standard-output of your Java program. Similarly, all of its standard-error will be sent to the standard-error of your Java program (which is extremely useful for troubleshooting errors and problems).
Notice the use of a try-with-resources statement for the BufferedWriter. This will automatically close the BufferedWriter. It’s both more concise and more reliable, since it effectively generates a hidden finally
block that performs the close.
Closing a Writer or OutputStream will always flush it, so an explicit call to flush()
is not needed.