Replace <Unknown Source> in Java Rhino (JSR223) with actual file name
Asked Answered
M

4

8

In my code, all of the scripts are contained in .js files. Whenever one of the scripts contains an error, I get this:

javax.script.ScriptException: sun.org.mozilla.javascript.internal.EcmaError: ReferenceError: "nonexistant" is not defined. (<Unknown source>#5) in <Unknown source> at line number 5

What bugs me is the <Unknown Source>. Multiple files are in one ScriptContext, and it can be hard to track down an error. It also looks horrible.

Is there a way to replace <Unknown Source> with the actual file name? None of the methods I see support passing a File object, so I'm really confused here.

Melissiamelita answered 21/5, 2010 at 19:50 Comment(0)
C
12

Use the ScriptEngine.FILENAME constant:

scriptEngine.put(ScriptEngine.FILENAME, scriptFile.toString());

Cacodyl answered 26/5, 2010 at 23:47 Comment(0)
G
6

The question hasn't been specifically asked yet, but I thought I'd offer this to anyone who stumbles upon this topic in the future: this will change when Java 8 is released and we move from Rhino to Nashorn as the underlying JavaScript engine. Under Nashorn, the file name is applied to the ScriptContext, rather than to the ScriptEngine itself:

ScriptContext context = new SimpleScriptContext();
context.setAttribute(ScriptEngine.FILENAME, "test.js", ScriptContext.ENGINE_SCOPE);
try
{
    engine.eval(script, context);
}
catch (ScriptException e)
{
    /* e.getFileName() will return "test.js" */
}

If you attempt to apply the file name using ScriptEngine.put(), as you do under Rhino, nothing will happen and your exceptions will return "<eval>" as the file name.

I would imagine that a few people will run into this issue in the coming months, so thought I'd offer it. This does not appear to be documented anywhere. I had to dig into the Nashorn source code to figure it out.

Gelman answered 11/2, 2014 at 20:29 Comment(1)
Bonus points for this one! Java 8 is long out and Java 9 coming shortly. :)Sclerodermatous
S
3

The Java 8 (Nashorn) way of setting the filename for the script engine through the ScriptContext figured out by mattj65816, works for the Rhino engine as well. So, I'd recommend using only

context.setAttribute(ScriptEngine.FILENAME, "test.js", ScriptContext.ENGINE_SCOPE);

since this piece of code works for both common JavaScript engines. You don't event need to create you own context, but only set the attribute to the engine's default context:

ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("JavaScript");
if (engine != null) {
    ScriptContext ctx = engine.getContext();
    ctx.setAttribute(ScriptEngine.FILENAME, "test.js", ScriptContext.ENGINE_SCOPE);
    ...
}
Stakeout answered 3/7, 2014 at 17:1 Comment(0)
I
0

perfect!

    ScriptEngine engine = new ScriptEngineManager().getEngineByExtension("js");
    // javax.script.filename
    engine.put(ScriptEngine.FILENAME, "test1.js");
    try {
        engine.eval("function throwError1(){throw new Error('test, haha')}");
    } catch (ScriptException e) {
    }       

    engine.put(ScriptEngine.FILENAME, "test2.js");
    try {
        engine.eval("function throwError2(){throw new Error('test2, haha')}");
    } catch (ScriptException e) {
    }
    try {
        engine.eval("throwError1()");
    } catch (ScriptException e) {
        System.out.println(e.getMessage());
    }
    try {
        engine.eval("throwError2()");
    } catch (ScriptException e) {
        System.out.println(e.getMessage());
    }

output :

Error: test, haha in test1.js at line number 1
Error: test2, haha in test2.js at line number 1
Interventionist answered 6/12, 2013 at 2:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.