JRuby:将stdout重定向到StringWriter会产生空输出

时间:2014-11-08 17:34:46

标签: java ruby jruby

我正在使用JRuby从Java程序动态运行Ruby脚本。脚本使用ARGV和包含称为" ctx"的附加信息的对象接收参数。然后,他们对信息执行某些操作并将结果返回到stdout,或者如果出现问题,则向stderr发送错误消息。这是我用来执行ruby脚本的代码:

String script = Joiner.on('\n').join(Files.readAllLines(Paths.get(path), StandardCharsets.UTF_8)); // read file from 
script = "require 'rubygems'\n" + script; // make gems work

ScriptingContainer rb = new ScriptingContainer(LocalVariableBehavior.PERSISTENT);
rb.setCompatVersion(CompatVersion.RUBY1_9);

String cwd = Paths.get("").toAbsolutePath().toString();
rb.setCurrentDirectory(cwd); // set working directory of scripts to working directory of application

StringWriter out = new StringWriter();
PrintWriter pwOut = new PrintWriter(out);

StringWriter err = new StringWriter();
PrintWriter pwErr = new PrintWriter(err);

String[] argsAry = args.split(" ");

rb.setOutput(pwOut);
rb.setError(pwErr);
rb.setArgv(argsAry); // set output writer, error writer and argv

rb.put("ctx", ctx); // add ctx to script container

try {
    rb.runScriptlet(script);
} catch(Throwable t) {
    logger.error("An exception occurred during JRuby execution! (ctx-id=" +
            ctx.getId() + ")", t);
}

out.close();
err.close(); // close writers

System.out.println(out.getBuffer()); // for debugging purposes

System.err.println(err.getBuffer()); // print stderr result to stderr,
return out.getBuffer().toString(); // and return stdout result

这是我用于测试的ruby脚本:

text = ARGV * ' '

puts text

现在我的问题是执行ruby脚本后两个缓冲区都是完全空的。我只是在stdout / err中得到两个空行,没有返回任何内容。使用另一个脚本,我确保脚本运行并且ctx成功传递给脚本。

我已经尝试过的事情:

  • 使用ctx中的变量将结果传递给java程序,使用rb.get检索它 - 尝试访问ctx的NullPointerException
  • 在ctx中使用变量,不使用rb.get - 变量为空
  • 在脚本中设置字符串,以便在尝试访问字符串时使用rb.get - NPE将其传递给程序
  • 根本不使用缓冲区 - 没有任何内容写入stdout / err
  • 只使用StringWriters而不是将它们与PrintWriters合并 - 没有变化,但the answer to this question建议我这样做
  • 使用另一个初始化容器的compat版本 - 无需更改
  • 使用其他LocalVariableBehavior - 无更改
  • 使用rb.setWriter / rb.setErrorWriter代替rb.setOutput / rb.setError - 无变更

任何帮助都将不胜感激。

1 个答案:

答案 0 :(得分:0)

经过一些实验,我设法通过在构造函数中将rb的LocalContextScope设置为THREADSAFE并在执行后刷新所有四个编写器来解决问题。