The use of Invoke can cause an Exception to be swallowed

UNCONFIRMED
Unassigned

Status

Rhino
Core
UNCONFIRMED
8 years ago
8 years ago

People

(Reporter: Dan Howard, Unassigned)

Tracking

Details

(Reporter)

Description

8 years ago
User-Agent:       Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 ( .NET CLR 3.5.30729)
Build Identifier: Java 1.6.20 Mozilla Rhino (1.6 release 2)

In the case where you use Invocable to call a function from a script - and that function calls a method in Java and that method throws a run time exception (say null pointer) - the exception logged will not have a "Caused By" to point to the error in the Java code. You only get the line number from the Script and the line where Java used Invoke.

Reproducible: Always

Steps to Reproduce:
//*****
//Save this as callback.js
//*****
var someNumber = 0;

function start() {
    log.info("started....");
    someNumber = 20;

    log.info(this);
    test.callFromRhino(junk);
}

function junk() {
    log.info("called back " + someNumber);
}
//**********************
***********************
// Save this Java class and run. Requires LOG4J.
***********************
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;

import javax.script.*;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.util.List;

public class LoseException {

    private ScriptEngineManager mgr = new ScriptEngineManager();
    private ScriptEngine engine = mgr.getEngineByName("JavaScript");

    private static final Logger log = LogManager.getLogger(LoseException.class);


    public static void main(String args[]) {

        ScriptEngineManager mgr = new ScriptEngineManager();
        List<ScriptEngineFactory> factories =
                mgr.getEngineFactories();
        for (ScriptEngineFactory factory : factories) {
            System.out.println("ScriptEngineFactory Info");
            String engName = factory.getEngineName();
            String engVersion = factory.getEngineVersion();
            String langName = factory.getLanguageName();
            String langVersion = factory.getLanguageVersion();
            System.out.printf("\tScript Engine: %s (%s)\n",
                    engName, engVersion);
            List<String> engNames = factory.getNames();
            for (String name : engNames) {
                System.out.printf("\tEngine Alias: %s\n", name);
            }
            System.out.printf("\tLanguage: %s (%s)\n",
                    langName, langVersion);
        }

        new LoseException();
    }

    public LoseException() {

        CompiledScript script = null;
        try {
            URL url = getClass().getResource("/callback.js");
            InputStream is = getClass().getResourceAsStream("/callback.js");

            Compilable compilingEngine = (Compilable) engine;

            Reader reader = new InputStreamReader(is);
            script = compilingEngine.compile(reader);

            Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
            bindings.put("log", log);
            bindings.put("test", this);
            script.eval(bindings);

        } catch (ScriptException e) {
            log.error(e.getMessage(), e);
        }

        Invocable invocable = (Invocable) script.getEngine();
        try {
            invocable.invokeFunction("start");
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }

    }

    public void callFromRhino(Runnable callback) {
        // The start function calls this method.
        // We'll force a null pointer exception
        log.info(callback.getClass().getName());
        String x = null;
        x.substring(1);

        callback.run();
    }

}


Actual Results:  
ERROR May 29 2010 06:24:54 LoseException - sun.org.mozilla.javascript.internal.WrappedException: Wrapped java.lang.NullPointerException (<Unknown Source>#8) in <Unknown Source> at line number 8
javax.script.ScriptException: sun.org.mozilla.javascript.internal.WrappedException: Wrapped java.lang.NullPointerException (<Unknown Source>#8) in <Unknown Source> at line number 8
	at com.sun.script.javascript.RhinoScriptEngine.invoke(RhinoScriptEngine.java:184)
	at com.sun.script.javascript.RhinoScriptEngine.invokeFunction(RhinoScriptEngine.java:142)
	at LoseException.<init>(LoseException.java:76)
	at LoseException.main(LoseException.java:50)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)


Expected Results:  
ERROR May 29 2010 06:24:54 LoseException - sun.org.mozilla.javascript.internal.WrappedException: Wrapped java.lang.NullPointerException (<Unknown Source>#8) in <Unknown Source> at line number 8
javax.script.ScriptException: sun.org.mozilla.javascript.internal.WrappedException: Wrapped java.lang.NullPointerException (<Unknown Source>#8) in <Unknown Source> at line number 8
	at com.sun.script.javascript.RhinoScriptEngine.invoke(RhinoScriptEngine.java:184)
	at com.sun.script.javascript.RhinoScriptEngine.invokeFunction(RhinoScriptEngine.java:142)
	at LoseException.<init>(LoseException.java:76)
	at LoseException.main(LoseException.java:50)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
WITH CAUSED BY to show line number from the Java method were the null pointer actually happened.




I would have expected the full stack trace. The WrappedException seems to lose the actual cause.
(Reporter)

Comment 1

8 years ago
It might be: http://bugs.sun.com/view_bug.do?bug_id=6474943
You need to log in before you can comment on or make changes to this bug.