JSR-223: ScriptContext Writers Ignored?


#1

ScriptEngine has a context property of type ScriptContext, and that has writer and errorWriter properties. These are supposed to be where scripts emit their stdout and stderr to. See this for example.

However, I cannot seem to get that working with the Kotlin engine.

Starting with the official test sample project, I added these four tests:

    @Test
    fun testSystemOutRedir() {
        val engine = ScriptEngineManager().getEngineByExtension("kts") as KotlinJsr223JvmLocalScriptEngine

        val out = ByteArrayOutputStream()

        System.setOut(PrintStream(out))

        val comp1 = engine.compile("println(1)")
        val res1 = comp1.eval()
        Assert.assertNull(res1)
        
        Assert.assertEquals("1\n", out.toString())
    }

    @Test
    fun testEngineOutRedir() {
        val engine = ScriptEngineManager().getEngineByExtension("kts") as KotlinJsr223JvmLocalScriptEngine

        val out = StringWriter()

        engine.context.writer = PrintWriter(out)

        val comp1 = engine.compile("println(1)")
        val res1 = comp1.eval()
        Assert.assertNull(res1)
        
        Assert.assertEquals("1\n", out.buffer.toString())
    }

    @Test
    fun testSystemErrRedir() {
        val engine = ScriptEngineManager().getEngineByExtension("kts") as KotlinJsr223JvmLocalScriptEngine

        val out = ByteArrayOutputStream()

        System.setErr(PrintStream(out))

        val comp1 = engine.compile("System.err.println(1)")
        val res1 = comp1.eval()
        Assert.assertNull(res1)
        
        Assert.assertEquals("1\n", out.toString())
    }

    @Test
    fun testEngineErrRedir() {
        val engine = ScriptEngineManager().getEngineByExtension("kts") as KotlinJsr223JvmLocalScriptEngine

        val out = StringWriter()

        engine.context.errorWriter = PrintWriter(out)

        val comp1 = engine.compile("System.err.println(1)")
        val res1 = comp1.eval()
        Assert.assertNull(res1)
        
        Assert.assertEquals("1\n", out.buffer.toString())
    }

The two testSystem...() functions test redirecting stdout and stderr by means of System.setOut() and System.setErr(). Those tests succeed.

The two testEngine...() functions test redirecting stdout and stderr by means of ScriptContext. Those tests fail.

I also have this test that both sets the system stdout and overrides the ScriptContent writer:

    @Test
    fun testComboOutRedir() {
        val engine = ScriptEngineManager().getEngineByExtension("kts") as KotlinJsr223JvmLocalScriptEngine

        val out = ByteArrayOutputStream()

        System.setOut(PrintStream(out))

        val outWriter = StringWriter()

        engine.context.writer = PrintWriter(outWriter)

        val comp1 = engine.compile("println(1)")
        val res1 = comp1.eval()
        Assert.assertNull(res1)
        
        Assert.assertEquals("1\n", out.toString())
        Assert.assertEquals("1\n", outWriter.buffer.toString())
    }

This fails on the final Assert.assertEquals() call. In particular, this shows that even though I specifically request to have stdout go to my PrintWriter, stdout still goes to the system stdout.

Am I doing something wrong?

Thanks!


#2

It is a known problem - https://youtrack.jetbrains.com/issue/KT-22398, please comment and vote there.