我有一个应用程序,除其他外,通过java.lang.reflect
运行Java方法。它通常正常运作;但是,用户将其与其中一个JAR一起使用,并且它有所破坏。
正如您在下面的代码中看到的,我尝试从方法中捕获stdout
和stdin
。但是,在调用该方法时,实际上只捕获了方法流到stdout
的第一行。
以下是相关代码。如果您需要查看更多代码,请告诉我们,我还会添加更多代码:
String retVal = "";
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayOutputStream err = new ByteArrayOutputStream();
PrintStream origOut = System.out;
PrintStream origErr = System.err;
System.setOut(new PrintStream(out));
System.setErr(new PrintStream(err));
Exception myException = null;
try {
Object myRetVal = null;
myRetVal = m.invoke(obj, convertedMethodArguments);
if (myRetVal != null)
retVal = myRetVal.toString();
} catch (Exception e) {
myException = e;
}
returnObj.addProperty("stdout", out.toString());
returnObj.addProperty("stderr", err.toString());
returnObj.addProperty("rv", retVal);
returnObj.addProperty("rt", m.getReturnType().toString());
if (myException != null && myException.getCause() != null)
returnObj.addProperty("exception", myException.getCause().toString());
else
returnObj.addProperty("exception", "");
System.setOut(origOut);
System.setErr(origErr);
System.out.print(new Gson().toJson(returnObj));
// TODO: remove, debug purposes only
// Should use normal stdout
try {
System.out.println();
m.invoke(obj, convertedMethodArguments);
} catch (Exception e) {
System.out.println(e.toString());
}
当我执行上面的代码时,它只打印出stdout
的第一行。但是,在代码块的底部,我再次调用该方法,但这次没有任何重定向,我从方法中获得了所有stdout
。
非常感谢任何帮助!
编辑#1:好的,明白了。为了好玩,我注释掉了我重定向默认系统流的两行(例如System.setOut
和System.setErr
)。随着这些消失,我现在希望在运行应用程序时直接将所有stdout
写入控制台。
我在代码的最后添加了一条消息(例如System.out.println("Testing...");
),这是它执行的最后一件事。当我测试应用时,我得到stdout
的第一行,然后是我的测试消息,然后是stdout
的其余部分。
我不知道这里发生了什么。
编辑#2: Per @ Titus的建议,我调查了我调用的方法是否正在脱离自己的线程。原来,它是。创建了两个线程AWT-AppKit
和AWT-Shutdown
。前一个线程似乎保持在RUNNABLE
状态,而后一个线程保持在TIMED_WAITING
状态。
随着时间的推移,AWT-Shutdown
线程消失,但另一个线程在其RUNNABLE
状态下保持活跃状态。一旦我的应用程序退出,我相信我调用的方法也会退出,此时额外的消息会显示在屏幕上(这解释了为什么我无法捕获STDOUT
的这一部分)
我不明白为什么这种方法不能在我的申请中终止。
答案 0 :(得分:1)
尝试在调用方法后刷新流。
以下是一个例子:
PrintStream outPR = new PrintStream(out);
System.setOut(outPR);
....
outPR.flush();
returnObj.addProperty("stdout", out.toString());
你甚至可以这样做:
System.setOut(new PrintStream(out, true));
....
System.out.println();
returnObj.addProperty("stdout", out.toString());
当PrintStream
(新行)写入\n
时,{{1}}会自动刷新(如果您使用我使用过的构造函数)。
根据您的问题的编辑,您正在调用的方法可能正在创建新线程,这意味着在方法返回后,这些新线程可能会打印到控制台。
如果是这种情况,您必须等到此线程完成才能获得所有输出。