Closed Bug 290034 Opened 20 years ago Closed 20 years ago

Cannot catch in JavaScript the original exception thrown by a host object implemented in Java (ScriptableObject subclass)

Categories

(Rhino Graveyard :: Core, defect)

x86
Windows XP
defect
Not set
normal

Tracking

(Not tracked)

RESOLVED FIXED

People

(Reporter: fernando.olcoz, Assigned: igor)

Details

Attachments

(2 files, 1 obsolete file)

User-Agent:       Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322)
Build Identifier: 

It seems there is an inconsistent behaviour between an Object implemented in 
JavaScript and a host object implemented in Java when it comes to throwing 
exceptions.
¿What is the contract a Java host object must honor in order to simulate the 
JS "throw" keyword and being catched in JS "unmodified"? In 1.5R5, it worked 
throwing a JavaScriptException(), but in 1.5R6 the JavaScriptException is 
placed inside a WrappedException.


Reproducible: Always

Steps to Reproduce:
1.Consider the following script:

// examples/problem-ok.js
function JSCounter(n)
{
    this.n = n;
    
    this.count = function() {
        if (n > 100) {
            throw java.lang.IllegalStateException("Greater than 100");
        }
        return n++;
    };
}

var c = new JSCounter(100);
try {
    print(c.count());
    print(c.count());
}
catch (e) {
    print(e);
    if (e.javaException) {
        // NEVER ENTERS HERE
        print(e.javaException);
    }
}

Executing the script above produces the following, expected, output:
js> load("examples/problem-ok.js")
100
java.lang.IllegalStateException: Greater than 100

2.Create a modified version of the supplied Counter host object that throws an 
exception when the count exceeds the 100 threshold:

// Counter.java
// ...
    public int jsGet_count() {
        if (count > 100) {
            throw new IllegalStateException("Greater than 100");
        }
        return count++;
    }
// ...

3.Run the following script, that uses the host object above:

// examples/problem.js

defineClass("Counter");

var c = new Counter(100);
try {
    print(c.count);
    print(c.count);
}
catch (e) {
    print(e);
    if (e.javaException) {
        // ALWAYS ENTERS HERE
        print(e.javaException);
    }
}

4.Running the above script yields the following result:
js> load("examples/problem.js")
100
JavaException: java.lang.IllegalStateException: Greater than 100
java.lang.IllegalStateException: Greater than 100

Actual Results:  
The host object implemented in Java is unable to reproduce the "throw" keyword 
behaviour.

Expected Results:  
There should be some way to write a host object in Java with members able to 
mimic the JS throw keyword.
Attached file Proposed change to ScriptRuntime.java (obsolete) —
This proposed change works for me:

    public static Scriptable newCatchScope(Throwable t,
					   Scriptable lastCatchScope,
					   String exceptionName,
					   Context cx, Scriptable scope)
    {
	Object obj;
	boolean cacheObj;

	// *** BEGIN
	// FO: Check whether t is a WrappedException that
	// contains a JavaScriptException; if so, unwrap
	if (t instanceof WrappedException) {
	    Throwable innerExc = ((WrappedException)t).getWrappedException();
	    if (innerExc instanceof JavaScriptException) {
		t = innerExc;
	    }
	}
	// *** END
	    
      getObj:
// rest of method unchanged
An approach that works for me is:

1. Host objects which wish to mimic the "throw" keyword behaviour in any of 
its members throw a JavaScriptException(originalException).

2. ScriptRuntime.newCatchScope(...) checks the passed Throwable is a 
WrappedException wrapping a JavaScriptException. In that case unwraps the 
JavaScriptException and proceeds as usual.
Attachment #180479 - Attachment is obsolete: true
I committed the fix
Status: NEW → RESOLVED
Closed: 20 years ago
Resolution: --- → FIXED
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: