Table 9.1 The LiveConnect Objects
Object
|
Description
|
JavaArray
|
A
wrapped Java array, accessed from within JavaScript code.
|
JavaClass
|
A
JavaScript reference to a Java class.
|
JavaObject
|
A
wrapped Java object, accessed from within JavaScript code.
|
JavaPackage
|
A
JavaScript reference to a Java package.
|
Note
Because Java is a strongly typed language and
JavaScript is weakly typed, the JavaScript runtime engine converts
argument values into the appropriate data types for the other
language when you use LiveConnect. See Data
Type Conversions for complete information.
In some
ways, the existence of the LiveConnect objects is transparent,
because you interact with Java in a fairly intuitive way. For
example, you can create a Java String object and
assign it to the JavaScript variable myString by using the
new operator
with the Java constructor, as follows:
var myString = new java.lang.String("Hello
world")
In the
previous example, the variable myString is a
JavaObject
because it holds an instance of the Java object String. As a
JavaObject,
myString has
access to the public instance methods of java.lang.String
and its superclass, java.lang.Object.
These Java methods are available in JavaScript as methods of
the JavaObject, and
you can call them as follows:
myString.length() // returns 11
The
Packages Object
If a
Java class is not part of the java, sun, or
netscape
packages, you access it with the Packages object.
For example, suppose the Redwood corporation uses a Java
package called redwood to
contain various Java classes that it implements. To create an
instance of the HelloWorld class
in redwood, you
access the constructor of the class as follows:
var red = new Packages.redwood.HelloWorld()
You can
also access classes in the default package (that is, classes that
don't explicitly name a package). For example, if the HelloWorld
class is directly in the CLASSPATH and not in a
package, you can access it as follows:
var red = new Packages.HelloWorld()
The
LiveConnect java, sun, and
netscape
objects provide shortcuts for commonly used Java packages. For
example, you can use the following:
var myString = new java.lang.String("Hello
world")
instead
of the longer version:
var myString = new
Packages.java.lang.String("Hello world")
Working with Java Arrays
When any
Java method creates an array and you reference that array in
JavaScript, you are working with a JavaArray. For example,
the following code creates the JavaArray
x with
ten elements of type int:
x
= java.lang.reflect.Array.newInstance(java.lang.Integer, 10)
Like the
JavaScript Array object,
JavaArray
has a length
property which returns the number of elements in the array. Unlike
Array.length,
JavaArray.length is a
read-only property, because the number of elements in a Java array
are fixed at the time of creation.
Package and Class References
Simple
references to Java packages and classes from JavaScript create the
JavaPackage
and JavaClass objects. In
the earlier example about the Redwood corporation, for example, the
reference Packages.redwood is a
JavaPackage
object. Similarly, a reference such as java.lang.String is a
JavaClass
object.
Most of
the time, you don't have to worry about the JavaPackage and
JavaClass
objects—you just work with Java packages and classes, and
LiveConnect creates these objects transparently.
In
JavaScript 1.3 and earlier, JavaClass objects are
not automatically converted to instances of java.lang.Class when
you pass them as parameters to Java methods—you must create a
wrapper around an instance of java.lang.Class. In the
following example, the forName method creates
a wrapper object theClass, which is then
passed to the newInstance method to
create an array.
// JavaScript 1.3
theClass = java.lang.Class.forName("java.lang.String")
theArray = java.lang.reflect.Array.newInstance(theClass, 5)
In
JavaScript 1.4 and later, you can pass a JavaClass object
directly to a method, as shown in the following example:
// JavaScript 1.4
theArray = java.lang.reflect.Array.newInstance(java.lang.String, 5)
Arguments of
Type char
In
JavaScript 1.4 and later, you can pass a one-character string to a
Java method which requires an argument of type char. For example, you
can pass the string "H" to the Character constructor
as follows:
c
= new java.lang.Character("H")
In
JavaScript 1.3 and earlier, you must pass such methods an integer
which corresponds to the Unicode value of the character. For example,
the following code also assigns the value "H" to the variable
c:
c
= new java.lang.Character(72)
Handling
Java Exceptions in JavaScript
When
Java code fails at run time, it throws an exception. If your
JavaScript code accesses a Java data member or method and fails, the
Java exception is passed on to JavaScript for you to handle.
Beginning with JavaScript 1.4, you can catch this exception in a
try...catch
statement.
For
example, suppose you are using the Java forName method to
assign the name of a Java class to a variable called
theClass.
The forName method
throws an exception if the value you pass it does not evaluate
to the name of a Java class. Place the forName
assignment statement in a try block to
handle the exception, as follows:
function getClass(javaClassName) {
try {
var theClass =
java.lang.Class.forName(javaClassName);
} catch (e) {
return ("The Java exception is "
+ e);
}
return theClass
}
In this
example, if javaClassName evaluates
to a legal class name, such as "java.lang.String", the assignment
succeeds. If javaClassName evaluates
to an invalid class name, such as "String", the getClass function
catches the exception and returns something similar to the following:
The Java exception is
java.lang.ClassNotFoundException: String
See
"Exception Handling Statements" on
page 78 for more information about JavaScript exceptions.
Java to
JavaScript Communication
If you
want to use JavaScript objects in Java, you must import the
netscape.javascript
package into your Java file. This package defines the following
classes:
-
-
netscape.javascript.JSObject
allows Java code to access JavaScript methods and properties.
-
netscape.javascript.JSException
allows Java code to handle JavaScript errors.
Starting
with JavaScript 1.2, these classes are delivered in a .jar file; in
previous versions of JavaScript, these classes are delivered in a .zip
file. See the Core
JavaScript Reference for more information about these classes.
To
access the LiveConnect classes, place the .jar or .zip file in the
CLASSPATH of
the JDK compiler in either of the following ways:
-
-
Create a CLASSPATH environment
variable to specify the path and name of .jar or .zip file.
-
Specify the location of .jar or .zip file
when you compile by using the -classpath command
line parameter.
For
example, in Navigator 4. 0 for Windows NT, the classes are delivered in
the java40.jar
file in the Program\Java\Classes
directory beneath the Navigator directory. You can specify an
environment variable in Windows NT by double-clicking the System icon
in the Control Panel and creating a user environment variable called
CLASSPATH with
a value similar to the following:
D:\Navigator\Program\Java\Classes\java40.jar
See the
Sun JDK documentation for more information about CLASSPATH.
Note
Because Java is a strongly typed language and
JavaScript is weakly typed, the JavaScript runtime engine converts
argument values into the appropriate data types for the other
language when you use LiveConnect. See Data
Type Conversions for complete information.
Using the
LiveConnect Classes
All
JavaScript objects appear within Java code as instances of
netscape.javascript.JSObject.
When you call a method in your Java code, you can pass it a
JavaScript object as one of its argument. To do so, you must
define the corresponding formal parameter of the method to be
of type JSObject.
Also,
any time you use JavaScript objects in your Java code, you should put
the call to the JavaScript object inside a try...catch statement
which handles exceptions of type netscape.javascript.JSException.
This allows your Java code to handle errors in JavaScript code
execution which appear in Java as exceptions of type
JSException.
Accessing
JavaScript with JSObject
For
example, suppose you are working with the Java class called
JavaDog. As
shown in the following code, the JavaDog constructor
takes the JavaScript object jsDog, which is defined
as type JSObject, as an
argument:
import netscape.javascript.*;
public class JavaDog
{
public String dogBreed;
public String dogColor;
public String dogSex;
// define the class constructor
public JavaDog(JSObject jsDog)
{
// use try...catch
to handle JSExceptions here
this.dogBreed =
(String)jsDog.getMember("breed");
this.dogColor =
(String)jsDog.getMember("color");
this.dogSex =
(String)jsDog.getMember("sex");
}
}
Notice
that the getMember method of
JSObject is
used to access the properties of the JavaScript object. The previous
example uses getMember to assign the
value of the JavaScript property jsDog.breed to the Java
data member JavaDog.dogBreed.
Note
A more realistic example would place the call to
getMember
inside a try...catch statement
to handle errors of type JSException. See
Handling JavaScript Exceptions in Java
for more information.
To get a
better sense of how getMember works, look
at the definition of the custom JavaScript object Dog:
function Dog(breed,color,sex) {
this.breed = breed
this.color = color
this.sex = sex
}
You can
create a JavaScript instance of Dog called
gabby
as follows:
gabby = new Dog("lab","chocolate","female")
If you
evaluate gabby.color, you can
see that it has the value "chocolate". Now suppose you create an
instance of JavaDog in your
JavaScript code by passing the gabby object to the
constructor as follows:
javaDog = new Packages.JavaDog(gabby)
If you
evaluate javaDog.dogColor, you
can see that it also has the value "chocolate", because the
getMember
method in the Java constructor assigns dogColor the value of
gabby.color.
Handling
JavaScript Exceptions in Java
When
JavaScript code called from Java fails at run time, it throws an
exception. If you are calling the JavaScript code from Java, you can
catch this exception in a try...catch statement.
The JavaScript exception is available to your Java code as an
instance of netscape.javascript.
JSException.
JSException
is a Java wrapper around any exception type thrown by JavaScript,
similar to the way that instances of JSObject are wrappers
for JavaScript objects. Use JSException when you
are evaluating JavaScript code in Java.
When you
are evaluating JavaScript code in Java, the following situations can
cause run-time errors:
-
-
The JavaScript code is not evaluated, either
due to a JavaScript compilation error or to some other error that
occurred at run time.
-
The JavaScript interpreter generates an
error message that is converted into an instance of
JSException.
-
Java successfully evaluates the JavaScript
code, but the JavaScript code executes an unhandled throw statement.
-
JavaScript throws an exception that is
wrapped as an instance of JSException. Use
the getWrappedException
method of JSException to
unwrap this exception in Java.
For
example, suppose the Java object eTest evaluates the
string jsCode
that you pass to it. You can respond to either type of run-time error
the evaluation causes by implementing an exception handler such as the
following:
import netscape.javascript.JSObject;
import netscape.javascript.JSException;
public class eTest {
public static Object doit(JSObject obj,
String jsCode) {
try {
obj.eval(jsCode);
} catch (JSException
e) {
if
(e.getWrappedException()==null)
return
e;
return
e.getWrappedException();
}
return null;
}
}
In this
example, the code in the try block attempts to
evaluate the string jsCode that you pass to
it. Let's say you pass the string "myFunction()" as the
value of jsCode. If
myFunction
is not defined as a JavaScript function, the JavaScript
interpreter cannot evaluate jsCode. The
interpreter generates an error message, the Java handler
catches the message, and the doit method
returns an instance of netscape.javascript.JSException.
However,
suppose myFunction is defined
in JavaScript as follows:
function myFunction() {
try {
if (theCondition == true) {
return
"Everything's ok";
} else {
throw
"JavaScript error occurred" ;
}
} catch (e) {
if (canHandle == true) {
handleIt();
} else {
throw e;
}
}
}
If
theCondition
is false, the function throws an exception. The exception is caught
in the JavaScript code, and if canHandle is true,
JavaScript handles it. If canHandle is false, the
exception is rethrown, the Java handler catches it, and the
doit method
returns a Java string:
JavaScript error occurred
See
"Exception Handling Statements" on
page 78 for complete information about JavaScript
exceptions.
Backward
Compatibility
In
JavaScript 1.3 and earlier versions, the JSException class had
three public constructors which optionally took a string argument,
specifying the detail message or other information for the exception.
The getWrappedException
method was not available.
Use a
try...catch
statement such as the following to handle LiveConnect exceptions in
JavaScript 1.3 and earlier versions:
try {
global.eval("foo.bar = 999;");
} catch (Exception e) {
if (e instanceof JSException) {
jsCodeFailed()";
} else {
otherCodeFailed();
}
}
In this
example, the eval statement fails if
foo is not
defined. The catch block executes
the jsCodeFailed method if
the eval
statement in the try block throws a
JSException;
the otherCodeFailed method
executes if the try block throws any
other error.
Data Type
Conversions
Because
Java is a strongly typed language and JavaScript is weakly typed, the
JavaScript runtime engine converts argument values into the appropriate
data types for the other language when you use LiveConnect. These
conversions are described in the following sections:
JavaScript
to Java Conversions
When you
call a Java method and pass it parameters from JavaScript, the data
types of the parameters you pass in are converted according to the
rules described in the following sections:
The return
values of methods of netscape.javascript.JSObject
are always converted to instances of java.lang.Object. The
rules for converting these return values are also described in these
sections.
For
example, if JSObject.eval returns a
JavaScript number, you can find the rules for converting this number
to an instance of java.lang.Object in
Number Values.
Number Values
When you
pass JavaScript number types as parameters to Java methods, Java
converts the values according to the rules described in the following
table:
Java parameter type
|
Conversion rules
|
double
|
|
java.lang.Double
java.lang.Object
|
A
new instance of java.lang.Double
is created, and the exact value is transferred to Java without
rounding and without a loss of magnitude or sign.
|
float
|
|
byte
char
int
long
short
|
-
-
Values are rounded using
round-to-negative-infinity mode.
-
Values which are too large or small to
be represented result in a run-time error.
-
NaN
can not be converted and results in a run-time error.
|
java.lang.String
|
Values are converted to strings. For
example,
|
boolean
|
-
-
0 and NaN values are
converted to false.
-
Other values are converted to true.
|
When a
JavaScript number is passed as a parameter to a Java method which
expects an instance of java.lang.String, the
number is converted to a string. Use the equals() method to
compare the result of this conversion with other string values.
Boolean Values
When you
pass JavaScript Boolean types as parameters to Java methods, Java
converts the values according to the rules described in the following
table:
Java parameter type
|
Conversion rules
|
boolean
|
All values are converted directly to the
Java equivalents.
|
lava.lang.Boolean
java.lang.Object
|
A
new instance of java.lang.Boolean
is created. Each parameter creates a new instance, not one
instance with the same primitive value.
|
java.lang.String
|
Values are converted to strings. For
example:
-
-
true becomes "true"
-
false becomes "false"
|
byte
char
double
float
int
long
short
|
-
-
true becomes 1
-
false becomes 0
|
When a
JavaScript Boolean is passed as a parameter to a Java method which
expects an instance of java.lang.String, the
Boolean is converted to a string. Use the == operator to compare the
result of this conversion with other string values.
String Values
When you
pass JavaScript string types as parameters to Java methods, Java
converts the values according to the rules described in the following
table:
Java parameter type
|
Conversion rules
|
lava.lang.String
java.lang.Object
|
JavaScript 1.4:
-
-
A JavaScript string is converted to an
instance of java.lang.String
with a Unicode value.
JavaScript 1.3 and earlier:
-
-
A JavaScript string is converted to an
instance of java.lang.String
with an ASCII value.
|
byte
double
float
int
long
short
|
All values are converted to numbers as
described in ECMA-262.
The JavaScript string value is converted
to a number according to the rules described in ECMA-262
|
char
|
JavaScript 1.4:
-
-
One-character strings are converted to
Unicode characters.
-
All other values are converted to
numbers.
JavaScript 1.3 and earlier:
-
-
All values are converted to numbers.
|
boolean
|
-
-
The empty string becomes false.
-
All other values become true.
|
Undefined Values
When you
pass undefined JavaScript values as parameters to Java methods, Java
converts the values according to the rules described in the following
table:
Java parameter type
|
Conversion rules
|
lava.lang.String
java.lang.Object
|
The value is converted to an instance of
java.lang.String whose value is the string "undefined".
|
boolean
|
The value becomes false.
|
double
float
|
The value becomes NaN.
|
byte
char
int
long
short
|
The value becomes 0.
|
The
undefined value conversion is possible in JavaScript 1.3 and later
versions only. Earlier versions of JavaScript do not support
undefined values.
When a
JavaScript undefined value is passed as a parameter to a Java method
which expects an instance of java.lang.String, the
undefined value is converted to a string. Use the == operator to
compare the result of this conversion with other string values.
Null Values
When you
pass null JavaScript values as parameters to Java methods, Java
converts the values according to the rules described in the following
table:
Java parameter type
|
Conversion rules
|
Any class
Any interface type
|
The value becomes null.
|
byte
char
double
float
int
long
short
|
The value becomes 0.
|
boolean
|
The value becomes false.
|
JavaArray and
JavaObject objects
In most
situations, when you pass a JavaScript JavaArray or
JavaObject
as a parameter to a Java method, Java simply unwraps the
object; in a few situations, the object is coerced into another
data type according to the rules described in the following
table:
Java parameter type
|
Conversion rules
|
Any interface or class that is
assignment-compatible with the unwrapped object.
|
The object is unwrapped.
|
java.lang.String
|
The object is unwrapped, the
toString
method of the unwrapped Java object is called, and the
result is returned as a new instance of java.lang.String.
|
byte
char
double
float
int
long
short
|
The object is unwrapped, and either of the
following situations occur:
-
-
If the unwrapped Java object has a
doubleValue
method, the JavaArray or
JavaObject is
converted to the value returned by this method.
-
If the unwrapped Java object does not
have a doubleValue
method, an error occurs.
|
boolean
|
In
JavaScript 1.3 and later versions, the object is unwrapped and
either of the following situations occur:
-
-
If the object is null, it is converted
to false.
-
If the object has any other value, it
is converted to true.
In
JavaScript 1.2 and earlier versions, the object is unwrapped
and either of the following situations occur:
-
-
If the unwrapped object has a
booleanValue method, the source object is converted to the
return value.
-
If the object does not have a
booleanValue method, the conversion fails.
|
An
interface or class is assignment-compatible with an unwrapped object
if the unwrapped object is an instance of the Java parameter type.
That is, the following statement must return true:
unwrappedObject instanceof
parameterType
JavaClass
objects
When you
pass a JavaScript JavaClass object as a
parameter to a Java method, Java converts the object according to the
rules described in the following table:
Java parameter type
|
Conversion rules
|
java.lang.Class
|
The object is unwrapped.
|
java.lang.JSObject
java.lang.Object
|
The JavaClass object
is wrapped in a new instance of java.lang.JSObject.
|
java.lang.String
|
The object is unwrapped, the
toString
method of the unwrapped Java object is called, and the
result is returned as a new instance of java.lang.String.
|
boolean
|
In
JavaScript 1.3 and later versions, the object is unwrapped and
either of the following situations occur:
-
-
If the object is null, it is converted
to false.
-
If the object has any other value, it
is converted to true.
In
JavaScript 1.2 and earlier versions, the object is unwrapped
and either of the following situations occur:
-
-
If the unwrapped object has a
booleanValue method, the source object is converted to the
return value.
-
If the object does not have a
booleanValue method, the conversion fails.
|
Other
JavaScript objects
When you
pass any other JavaScript object as a parameter to a Java method,
Java converts the object according to the rules described in the
following table:
Java parameter type
|
Conversion rules
|
java.lang.JSObject
java.lang.Object
|
The object is wrapped in a new instance of
java.lang.JSObject.
|
java.lang.String
|
The object is unwrapped, the
toString
method of the unwrapped object is called, and the result
is returned as a new instance of java.lang.String.
|
byte
char
double
float
int
long
short
|
The object is converted to a value using
the logic of the ToPrimitive
operator described in ECMA-262.
The PreferredType hint used with this operator is
Number.
|
boolean
|
In
JavaScript 1.3 and later versions, the object is unwrapped and
either of the following situations occur:
-
-
If the object is null, it is converted
to false.
-
If the object has any other value, it
is converted to true.
In
JavaScript 1.2 and earlier versions, the object is unwrapped
and either of the following situations occur:
-
-
If the unwrapped object has a
booleanValue method, the source object is converted to the
return value.
-
If the object does not have a
booleanValue method, the conversion fails.
|
Java to
JavaScript Conversions
Values
passed from Java to JavaScript are converted as follows:
-
-
Java byte, char, short, int, long, float, and
double are converted to JavaScript numbers.
-
A Java boolean is converted to a JavaScript
boolean.
-
An object of class netscape.javascript.JSObject
is converted to the original JavaScript object.
-
Java arrays are converted to a JavaScript
pseudo-Array object; this object behaves just like a JavaScript
Array
object: you can access it with the syntax arrayName[index]
(where index is an integer),
and determine its length with arrayName.length.
-
A Java object of any other class is converted
to a JavaScript wrapper, which can be used to access methods and
fields of the Java object:
-
-
Converting this wrapper to a string calls
the toString method
on the original object.
-
Converting to a number calls the
doubleValue
method, if possible, and fails otherwise.
-
Converting to a boolean in JavaScript 1.3
and later versions returns false if the object is null, and
true otherwise.
-
Converting to a boolean in JavaScript 1.2
and earlier versions calls the booleanValue
method, if possible, and fails otherwise.
-
Note that instances of java.lang.Double
and java.lang.Integer are converted to JavaScript objects, not
to JavaScript numbers. Similarly, instances of java.lang.String
are also converted to JavaScript objects, not to JavaScript
strings.
Java
String objects
also correspond to JavaScript wrappers. If you call a JavaScript method
that requires a JavaScript string and pass it this wrapper, you'll get
an error. Instead, convert the wrapper to a JavaScript string by
appending the empty string to it, as shown here:
var JavaString =
JavaObj.methodThatReturnsAString();
var JavaScriptString = JavaString + "";