1

I have created a class that dynamically compiles, loads in a CustomClassLoader, and executes an in-memory java source (i.e.: without class files) java source by invoking it's main method.

I need to capture the StdOut, StdIn, and StdErr, although it's not possible doing so in my current code. (Compiler API + Classloader + Reflection)

My requirements might be the same as asked in this question - and as suggested by the accepted answer - use java.lang.Process. This is easier if I had physical files available in the file system, but I have not in this case.

I am planning to remove the Classloader + Reflection strategy and use the suggestion instead; although, I'm not familiar in actually redirecting the Std* using the Process class.

How can I do this in Java 7? (Snippets are highly appreciated) Or more importantly, is there a better approach?

Community
  • 1
  • 1
Gx.Zero
  • 407
  • 1
  • 4
  • 10
  • Take a look at [*this*](http://stackoverflow.com/questions/12945537/how-to-set-output-stream-to-textarea/12945678#12945678), it redirects the stdout so you can process it any way you want...the process would, generally be the same for stderr and stdin – MadProgrammer Sep 17 '13 at 20:47

2 Answers2

0
  • Take a backup of the existing outputstream.

PrintStream realSystemOut = System.out;

  • Set it to other outputstream [ fileOutputStream, or some other streams] PrintStream overridePrintStream = new PrintStream(new FileOutputStream("log.txt"));

    System.setOut(overridePrintStream );

    ----- process -----

  • place the actual stream back to System.out

    System.setOut(realSystemOut);

Thanks

Manas Mukherjee
  • 5,270
  • 3
  • 18
  • 30
0

Java allows you to supply your own PrintStream to override stdout and stderr and a InputStream for stdin.

Personally, I don't like simply throwing away the original stream, cause I tend to only want to redirect or parse it, not stop it (although you could do that as well).

Here is a simple example of the idea...

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;

public class RedirectStdOut {

    public static void main(String[] args) {

        Consumer stdConsumer = new Consumer() {

            @Override
            public void processLine(StreamCapturer capturer, String text) {
            }

            @Override
            public void processCharacter(StreamCapturer capturer, char character) {
                capturer.getParent().print(character);
            }
        };

        StreamCapturer stdout = new StreamCapturer(stdConsumer, System.out);
        StreamCapturer stderr = new StreamCapturer(stdConsumer, System.err);

        System.setOut(new PrintStream(stdout));
        System.setErr(new PrintStream(stderr));

        System.out.println("This is a test");
        System.err.println("This is an err");

    }

    public static interface Consumer {

        public void processLine(StreamCapturer capturer, String text);

        public void processCharacter(StreamCapturer capturer, char character);
    }

    public static class StreamCapturer extends OutputStream {

        private StringBuilder buffer;
        private Consumer consumer;
        private PrintStream parent;
        private boolean echo = false;

        public StreamCapturer(Consumer consumer, PrintStream parent) {
            buffer = new StringBuilder(128);
            this.parent = parent;
            this.consumer = consumer;
        }

        public PrintStream getParent() {
            return parent;
        }

        public boolean shouldEcho() {
            return echo;
        }

        public void setEcho(boolean echo) {
            this.echo = echo;
        }

        @Override
        public void write(int b) throws IOException {
            char c = (char) b;
            String value = Character.toString(c);
            buffer.append(value);
            if (value.equals("\n")) {
                consumer.processLine(this, value);
                buffer.delete(0, buffer.length());
            }
            consumer.processCharacter(this, c);
            if (shouldEcho()) {
                parent.print(c);
            }
        }
    }

}

Now the StreamCapturer has the ability to echo the output if you want, I've turned it off to demonstrate the use of the Consumer. I would normally use the Consumer to process what is coming through the stream, based on your needs, you can wait for the complete line or process the individual characters...

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • Hmm. I get your idea. With this, however, I need the class to be "monitored" to always implement a _processLine_ like method right? In my case, I have no control over the code to be executed, so I can't seem to use this solution. Any thoughts? – Gx.Zero Sep 17 '13 at 22:10
  • If the class you are running outputs to stdout, then you can use this concept to capture what that class is writing and process it as required. – MadProgrammer Sep 17 '13 at 23:32