我意识到SO上有类似的问题,但它们并没有完全解决我的问题。
我想要一个方法,给定一个Class对象,将调用该类上的“main”方法,即public static void main(如果存在)并捕获该main方法的控制台输出。执行调用的类是非守护程序线程。
我已经有了部分代码,但是我不知道如何捕获控制台输出,最重要的是,如何只为这个特定的线程捕获它。这是我到目前为止所做的:
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();
}
}
我需要的只是一些代码,或者是如何捕获所调用方法的System.out和System.err输出的答案的链接。任何人都可以给予的帮助将不胜感激。
提前致谢!
编辑:这不仅仅用于测试,最终会投入生产。
编辑2 :这需要是线程安全的。其他线程可能会同时调用多个主要方法,我希望每个线程只捕获自己的特定输出。
答案 0 :(得分:5)
使用System.setOut,然后编写一个printstream的子类,它覆盖所有打印/写入方法,并记录数据,如果它来自您要监视的线程。
伪代码:
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);
}
}
然后您可以使用
创建和使用此流HackedPrintStream hps = new HackedPrintStream(System.out);
System.setOut(hps);
我真的建议你努力寻找另一种解决方案,因为这不是很好。
答案 1 :(得分:2)
由于您使用main()
方法 - 您是否需要它在同一个过程中?如果没有,您可以尝试将其创建为新流程(java.lang.Process
)。
Process
类提供了捕获StdOut
,StdErr
和/或StdIn
的必要方法。
注意因为一切都在它自己的进程中运行,所以线程安全应该没有问题。但是,您仍然需要找到位置,.class文件(或至少是根目录),以便您可以使用java here.goes.your.ClassName
运行/创建流程。
答案 2 :(得分:-1)
您可以使用System.setOut()和System.setErr(),但当然,输出也将被捕获用于程序的其余部分。