简体   繁体   中英

Java System.out not Being Redirected

I have a simple task of capturing all System.out output; I am however failing:

public class Main {
    ScriptEngine engine = new ScriptEngineManager().getEngineByName("js");
    ArrayList<String> history = new ArrayList<>();
    StringBuilder output = new StringBuilder();
    StringBuilder input = new StringBuilder();
    JPanel panel = new JPanel();
    JTextArea txt = new JTextArea();
    String PROMPT = "> ";
    Runnable show = new Runnable() {
            public void run() {
                txt.setText("");
                for (String line: history) txt.append(line + "\n");
                txt.append(PROMPT);
                txt.append(output.toString());
                txt.setCaretPosition(txt.getText().length());
            }
        };
    PrintStream os = new PrintStream(new OutputStream() {
            @Override
            public void write(int b) throws IOException {
                if (b == 13) {
                    history.add(input.toString());
                    input = new StringBuilder();
                    SwingUtilities.invokeLater(show);
                } else input.append((char)b);
            }
        });
    void init(String title) {
        panel.setLayout(new BorderLayout());
        txt.setLineWrap(true);
        txt.setFont(new Font("Courier", Font.PLAIN, 16));
        txt.setBackground(Color.BLACK);
        txt.setForeground(Color.GREEN);
        txt.setCaretColor(Color.GREEN);
        txt.setEditable(false);
        txt.setText(PROMPT);
        txt.addKeyListener(new KeyListener() {
            @Override
            public void keyTyped(KeyEvent e) {
                if (e.getKeyChar() == '\n') {
                    System.setOut(os);
                    System.setErr(os);
                    String result = output.toString();
                    history.add(PROMPT + result);
                    try {
                        engine.eval(result);
                    } catch (ScriptException ex) {
                        history.add(ex.toString());
                    }
                    output = new StringBuilder();
                } else {
                    output.append(e.getKeyChar());
                }
                SwingUtilities.invokeLater(show);
            }
            @Override
            public void keyPressed(KeyEvent e) {

            }
            @Override
            public void keyReleased(KeyEvent e) {

            }
        });
        panel.add(txt, BorderLayout.CENTER);
        JFrame frame = new JFrame(title);
        frame.setSize(650, 425);
        frame.setContentPane(panel);
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
    public static void main(String args[]) {
        new Main().init("javascript");
    }
}

I should note the output I am looking for comes from something like:

new ScriptEngineManager().getEngineByName("js").eval("print(\"test\");");

The output is not going anywhere other than normal STDOUT aka System.out . Why?

ScriptEngine output redirection:

To redirect the output of a script you first have to get its ScriptContext instance, that has a method called setWriter(Writer). That sets the output of the ScriptEngine.

For that you first need a Writer. This can be simple like this one:

public class CaptureWriter extends Writer
{

    private StringBuilder m_build;

    public CaptureWriter(StringBuilder build)
    {
        m_build = build;
    }

    @Override
    public void write(char[] cbuf, int off, int len) throws IOException
    {
        m_build.insert(m_build.length(), cbuf, off, len);
    }

    @Override
    public void flush() throws IOException
    {
    }

    @Override
    public void close() throws IOException
    {
    }

}

This writes all input into a StringBuilder.

Then you register it into a ScriptContext

ScriptEngine engine = new ScriptEngineManager().getEngineByName("js");

engine.getContext().setWriter(new CaptureWriter(m_mess));

When running this simple program:

StringBuilder build = new StringBuilder();

    ScriptEngine engine = new ScriptEngineManager().getEngineByName("js");

    engine.getContext().setWriter(new CaptureWriter(build));

    try
    {
        engine.eval("print(\"Hello\")");
        engine.eval("print(\"World\")");
        engine.eval("print(\"You\")");
        engine.eval("print(\"There\")");
    } catch(ScriptException e)
    {
        e.printStackTrace();
    }

    System.out.println(build);

The output is the buffered output of the script:

Hello
World
You
There

You can of course hook anything into the write method of the Writer implementation, this is just an example.

System.out redirection:

To capture the System.out output you have to make your own PrintStream implementation, it can be very simple like:

public class Capture extends PrintStream
{

    private StringBuilder m_build;

    public Capture(OutputStream out, StringBuilder build)
    {
        super(out);

        m_build = build;
    }

    public void println(String s)
    {
        super.println(s);

        m_build.append(s + "\n");
    }

}

Then you need to register it in the runtime:

StringBuilder build = new StringBuilder();

System.setOut(new Capture(System.out, build));

Then every time System.out.println is called it works like the overriding PrintStream should and the message gets written into the provided StringBuilder.

To capture other messages you'll need to override other methods.

You can capture System.out be providing a PrintStream that you control ... try something like this

ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(baos);
PrintStream old = System.out;
System.setOut(ps);
System.out.println("This will be captured :P");
System.out.flush();
System.setOut(old);
System.out.println("He is what was captured : " + baos.toString());

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM