Java – Capture Console Output of a Specific Thread in Java

consolejavamultithreading

I realize there are similar questions on SO, but they don't quite solve my problem.

I would like a method that, given a Class object, will invoke the "main" method, that is to say, public static void main, on that Class (if it exists) and capture the console output of that main method. The class doing the invocation is a non-daemon thread.

I have part of the code already, but I'm not sure how to capture the console output, and on top of that, how to only capture it for *this specific thread. Here's what I have so far:

public class Output extends Thread {
    private Class testClass;

    public Output(Class clazz) {
        this.testClass = clazz;
    }

    private Method getMainMethod(Class clazz) {
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            if (isMainMethod(method)) { 
                return method;
            }
        }

        return null;
    }

    private Boolean isMainMethod(Method method) {
        return (method.getName().equals("main") &&
                Modifier.isStatic(method.getModifiers()) &&
                method.getReturnType().equals(Void.class));
    }

    public void run() {
        Method mainMethod = null;

        if ((mainMethod = getMainMethod(this.testClass)) == null) {
            //if there's no static void main method, throw exception
            throw new YouFuckedItUpException();
        }

        mainMethod.invoke(this.testClass, new String[0]);

        return heresWhereImStuckIWantToCaptureTheConsoleOutputAndReturnIt();
    }
}

All I need is some code to, or a link to an answer on how to, capture the System.out and System.err output of the method being invoked. Any help someone can give would be much appreciated.

Thanks in advance!

EDIT: This is NOT for testing only, this will eventually be something put into production.

EDIT 2: This will need to be thread-safe. Multiple main methods will be invoked by other threads possibly at the same time, and I want each thread to only capture its own specific output.

Best Answer

Use System.setOut and then write a subclass of printstream that overrides all print/write methods and logs the data if it comes from a thread you want to monitor.

Pseudocode:

public class HackedPrintStream extends PrintStream {
    private PrintStream originalStream;
    private HashMap<Thread, PrintStream> loggerStreams = new HashMap<Thread, PrintStream>();

    public HackedPrintStream(PrintStream originalStream) {
        this.originalStream = originalStream;
    }

    public synchronized void logForThread(Thread threadToLogFor, PrintStream streamToLogTo) {
        loggerStreams.put(threadToLogFor, streamToLogTo);
    }

    /** example overridden print method, you need to override all */
    public synchronized void println(String ln) {
        PrintStream logPS = loggerStreams.get(Thread.currentThread());
        if (logPS != null) { logPS.println(ln); }
        originalStream.println(ln);
    }
}

Then you can create and use this stream with

HackedPrintStream hps = new HackedPrintStream(System.out);
System.setOut(hps);

I would really advise you to look hard for another solution though, as this is not pretty.