从java.lang.reflect方法调用中捕获stdout

时间:2017-11-08 04:56:46

标签: java reflection

我有一个应用程序,除其他外,通过java.lang.reflect运行Java方法。它通常正常运作;但是,用户将其与其中一个JAR一起使用,并且它有所破坏。

正如您在下面的代码中看到的,我尝试从方法中捕获stdoutstdin。但是,在调用该方法时,实际上只捕获了方法流到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.setOutSystem.setErr)。随着这些消失,我现在希望在运行应用程序时直接将所有stdout写入控制台。

我在代码的最后添加了一条消息(例如System.out.println("Testing...");),这是它执行的最后一件事。当我测试应用时,我得到stdout的第一行,然后是我的测试消息,然后是stdout的其余部分。

我不知道这里发生了什么。

编辑#2: Per @ Titus的建议,我调查了我调用的方法是否正在脱离自己的线程。原来,它是。创建了两个线程AWT-AppKitAWT-Shutdown。前一个线程似乎保持在RUNNABLE状态,而后一个线程保持在TIMED_WAITING状态。

随着时间的推移,AWT-Shutdown线程消失,但另一个线程在其RUNNABLE状态下保持活跃状态​​。一旦我的应用程序退出,我相信我调用的方法也会退出,此时额外的消息会显示在屏幕上(这解释了为什么我无法捕获STDOUT的这一部分)

我不明白为什么这种方法不能在我的申请中终止。

1 个答案:

答案 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}}会自动刷新(如果您使用我使用过的构造函数)。

根据您的问题的编辑,您正在调用的方法可能正在创建新线程,这意味着在方法返回后,这些新线程可能会打印到控制台。

如果是这种情况,您必须等到此线程完成才能获得所有输出。