Printing a Java InputStream from a Process

UPDATE: I found a crucial part to why this probably isn't working! I used System.setOut(out); where out is a special PrintStream to a JTextArea

This is the code, but the issue I'm having is that the information is only printed out once I end the process.

public Constructor() {
    main();
}

private void main() {
    btnStart.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            try {
                ProcessBuilder builder = new ProcessBuilder("java", textFieldMemory.getText(), "-jar", myJar);
                Process process = builder.start();
                InputStream inputStream = process.getInputStream();
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream), 1);
                String line;
                while ((line = bufferedReader.readLine()) != null) {
                    System.out.println(line);
                }
                inputStream.close();
                bufferedReader.close();
            } catch (IOException ioe) {
                ioe.printStackTrace();
            }
        }
    });
} 

Current output:

Line 1
Line 2
Line 3
Line 4
Line 5

This is the correct output, but it is only being printed as one big block when I end the process.

Does anyone know what the issue is? If so can you help explain to me why this is happening, thank-you in advance.


Processing the output stream of the process in a separate thread might help here. You also want to explicitly wait for the process to end before continuing with your logic:

ProcessBuilder builder = new ProcessBuilder("java",
        textFieldMemory.getText(), "-jar", myJar);
final Process process = builder.start();
final Thread ioThread = new Thread() {
    @Override
    public void run() {
        try {
            final BufferedReader reader = new BufferedReader(
                    new InputStreamReader(process.getInputStream()));
            String line = null;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
            reader.close();
        } catch (final Exception e) {
            e.printStackTrace();
        }
    }
};
ioThread.start();

process.waitFor();

Basically, from what little information there is, it sounds like your executing the process and reading the InputStream from within the Event Dispatching Thread.

Anything to blocks the EDT will prevent it from processing repaint requests, instead, you should use something like a SwingWorker which has functionality to allow you to update the UI from with the EDT.

Take a look at Concurrency in Swing for more details

enter image description here

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class PBDemo {

    public static void main(String[] args) throws Exception {
        new PBDemo();
    }

    public PBDemo() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        public TestPane() {
            setLayout(new BorderLayout());
            JTextArea ta = new JTextArea();
            add(new JScrollPane(ta));

            new ProcessWorker(ta).execute();
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }
    }

    public interface Consumer {
        public void consume(String value);            
    }

    public class ProcessWorker extends SwingWorker<Integer, String> implements Consumer {

        private JTextArea textArea;

        public ProcessWorker(JTextArea textArea) {
            this.textArea = textArea;
        }

        @Override
        protected void process(List<String> chunks) {
            for (String value : chunks) {
                textArea.append(value);
            }
        }

        @Override
        protected Integer doInBackground() throws Exception {
            // Forced delay to allow the screen to update
            Thread.sleep(5000);
            publish("Starting...\n");
            int exitCode = 0;
            ProcessBuilder pb = new ProcessBuilder("java.exe", "-jar", "HelloWorld.jar");
            pb.directory(new File("C:\\DevWork\\personal\\java\\projects\\wip\\StackOverflow\\HelloWorld\\dist"));
            pb.redirectError();
            try {
                Process pro = pb.start();
                InputConsumer ic = new InputConsumer(pro.getInputStream(), this);
                System.out.println("...Waiting");
                exitCode = pro.waitFor();

                ic.join();

                System.out.println("Process exited with " + exitCode + "\n");

            } catch (Exception e) {
                System.out.println("sorry" + e);
            }
            publish("Process exited with " + exitCode);
            return exitCode;
        }

        @Override
        public void consume(String value) {
            publish(value);
        }
    }

    public static class InputConsumer extends Thread {

        private InputStream is;
        private Consumer consumer;

        public InputConsumer(InputStream is, Consumer consumer) {
            this.is = is;
            this.consumer = consumer;
            start();
        }

        @Override
        public void run() {
            try {
                int in = -1;
                while ((in = is.read()) != -1) {
//                    System.out.print((char) in);
                    consumer.consume(Character.toString((char)in));
                }
            } catch (IOException exp) {
                exp.printStackTrace();
            }
        }
    }
}