Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

java

rhino

jsr223

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.

like image 441
TheLQ Avatar asked May 21 '10 19:05

TheLQ


3 Answers

Use the ScriptEngine.FILENAME constant:

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

like image 55
Kevin Krouse Avatar answered Nov 09 '22 03:11

Kevin Krouse


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.

like image 28
mattj65816 Avatar answered Nov 09 '22 04:11

mattj65816


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);
    ...
}
like image 31
cklein05 Avatar answered Nov 09 '22 05:11

cklein05