LiveConnect Exceptions
by Chris Cooper <ccooper@neon.polkaroo.net>

Last modified: Wed Dec 9 15:00:16 EST 1998

LiveConnect enables communication between JavaScript and Java applets in a page and between JavaScript and plug-ins loaded on a page. However, until now, Java and JavaScript were unable to catch exceptions generated by the other language. The implementation of LiveConnect exception handling now makes graceful error recovery between the two languages possible.

Get there quick:


Catching JavaScript exceptions

Let's start with the most basic example. JavaScript exceptions can be thrown using the throw keyword, and caught using a try / catch block.

eg. the following example JavaScript code...

try {
	throw 'Thrown JS exception';
} catch (e) {
        print("Exception caught: " + e.toString());
}
        

...would catch something like this:

Exception caught: Thrown JS exception

Any JS type (string, number, boolean, Object, undefined, null) can be thrown as an exception. More examples of this are listed below


Catching Java exceptions in JavaScript

Java exceptions are thrown back into JavaScript when a line of JavaScript code tries to access a Java member variable or method and fails.

eg. the following example JavaScript code...

try {
        java.lang.Class.forName("blah");
} catch (e) {
        print("Java Exception caught: " + e);
}
        

...would catch something like this:

Java Exception caught: java.lang.ClassNotFoundException: blah


Catching JavaScript exceptions thrown through Java in JavaScript

Imagine this scenario: A line of JavaScript makes a call into Java. While in Java land, this code makes a call back into JavaScript where it triggers an exception. LiveConnect propagates this exception back through Java to the original JavaScript layer where it can be caught.

eg. the following example JavaScript code...

try {
	Packages.Test.doit(this, "throw 'foo';");
} catch (e) {
        print("Exception caught: " + e.toString());
}
        

...would first call into Java and attempt to evaluate the JavaScript code in the second argument (see the listing for Test.java below for the internals). If successful, it would catch something like this:

Exception caught: foo

Just like the simple JavaScript exceptions above, any JS type (string, number, boolean, Object, undefined, null) can be throw across the two languages and the type information will be preserved. More examples of this are listed below


Examples

The following two files can be used to test the various features of LiveConnect exception handling.

Download: (Use RightClick-"Save Link As...")

test.js
Test.java

Below is a listing of both files, followed by a listing of the output generated when the files are run through the LiveConnect engine (jsj or jsj.exe).

test.js
print("Throwing JS Exception");
try {
	throw 'Thrown JS exception';
	print("\tNo exception caught\n");	
} catch (e) {
        print("\tException caught: " + e.toString());
	print("\tJS Type of exception: " + typeof e + "\n");
}

print("Triggering Java ClassNotFoundException");
try {
        str = java.lang.Class.forName("blah");
	print("\tNo exception caught: " + str + "\n");
} catch (e) {
        print("\tException caught: " + e.toString());
	print("\tJS Type of exception: " + typeof e + "\n");
}

print("Throwing string: Packages.Test.doit(this, throw 'foo';)");
try {
	str = Packages.Test.doit(this, "throw 'foo';");
	print("\tNo exception caught: " + str + "\n");
} catch ( e ) {
	print("\tException caught: " + e.toString());
	print("\tJS Type of exception: " + typeof e + "\n");
}

print("Throwing number: Packages.Test.doit(this, throw 42;)");
try {
	str = Packages.Test.doit(this, "throw 42;");
	print("\tNo exception caught: " + str + "\n");
} catch ( e ) {
	print("\tException caught: " + e.toString());
	print("\tJS Type of exception: " + typeof e + "\n");
}

print("Throwing number: Packages.Test.doit(this, throw 4.2;)");
try {
	str = Packages.Test.doit(this, "throw 4.2;");
	print("\tNo exception caught: " + str + "\n");
} catch ( e ) {
	print("\tException caught: " + e.toString());
	print("\tJS Type of exception: " + typeof e + "\n");
}

print("Throwing boolean: Packages.Test.doit(this, throw false;)");
try {
	str = Packages.Test.doit(this, "throw false;");
	print("\tNo exception caught: " + str + "\n");
} catch ( e ) {
	print("\tException caught: " + e.toString());
	print("\tJS Type of exception: " + typeof e + "\n");
}

print("Throwing Object (new Date): Packages.Test.doit(this, throw new Date();)");
try {
	str = Packages.Test.doit(this, "throw new Date();");
	print("\tNo exception caught: " + str + "\n");
} catch ( e ) {
	print("\tException caught: " + e.toString());
	print("\tJS Type of exception: " + typeof e + "\n");
}

print("Throwing Object (new String): Packages.Test.doit(this, throw new String();)");
try {
	str = Packages.Test.doit(this, "throw new String();");
	print("\tNo exception caught: " + str + "\n");
} catch ( e ) {
	print("\tException caught: " + e.toString());
	print("\tJS Type of exception: " + typeof e + "\n");
}

print("Throwing Object ({a:42}): Packages.Test.doit(this, throw {a:42};)");
try {
	str = Packages.Test.doit(this, "throw {a:42};");
	print("\tNo exception caught: " + str + "\n");
} catch ( e ) {
	print("\tException caught: " + e.toString());
	print("\tJS Type of exception: " + typeof e + "\n");
}

print("Throwing undefined: Packages.Test.doit(this, throw undefined)");
try {
        str = Packages.Test.doit(this, "throw undefined;");
        print("\tNo exception caught: " + str + "\n");
} catch ( e ) {
        print("\tException caught.");
        print("\tJS Type of exception: " + typeof e + "\n");
}

print("Throwing null: Packages.Test.doit(this, throw null)");
try {
        str = Packages.Test.doit(this, "throw null;");
        print("\tNo exception caught: " + str + "\n");
} catch ( e ) {
        print("\tException caught.");
        print("\tType of exception: " + typeof e);
}
	    
Test.java
import netscape.javascript.JSObject;

public class Test {

    public static Object doit(JSObject obj, String code) {
	obj.eval(code);
	return null;
    }
}
	    
Output:
[user@machine liveconnect]$ Linux_All_DBG.OBJ/jsj test.js
Throwing JS Exception
        Exception caught: Thrown JS exception
        JS Type of exception: string

Triggering Java ClassNotFoundException
        Exception caught: java.lang.ClassNotFoundException: blah
        JS Type of exception: object

Throwing string: Packages.Test.doit(this, throw 'foo';)
        Exception caught: foo
        JS Type of exception: string

Throwing number: Packages.Test.doit(this, throw 42;)
        Exception caught: 42
        JS Type of exception: number

Throwing number: Packages.Test.doit(this, throw 4.2;)
        Exception caught: 4.2
        JS Type of exception: number

Throwing boolean: Packages.Test.doit(this, throw false;)
        Exception caught: false
        JS Type of exception: boolean

Throwing Object (new Date): Packages.Test.doit(this, throw new Date();)
        Exception caught: Mon Dec 07 10:09:05 GMT-0500 (EST) 1998
        JS Type of exception: object

Throwing Object (new String): Packages.Test.doit(this, throw new String();)
        Exception caught: 
        JS Type of exception: object

Throwing Object ({a:42}): Packages.Test.doit(this, throw {a:42};)
        Exception caught: [object Object]
        JS Type of exception: object

Throwing undefined: Packages.Test.doit(this, throw undefined)
        Exception caught.
        JS Type of exception: undefined

Throwing null: Packages.Test.doit(this, throw null)
        Exception caught.
        Type of exception: object
[user@machine liveconnect]$

Troubleshooting


Chris Cooper
Last modified: Wed Dec 9 15:00:16 EST 1998