22.4 LiveConnect Data TypesTo understand how LiveConnect does its job of connecting JavaScript to Java, you have to understand the JavaScript data types that LiveConnect uses. The following sections explain these JavaScript data types. Although Internet Explorer uses a different technology, an understanding of how LiveConnect works will also help you understand the workings of IE. Some of the LiveConnect data types described here have analogs in IE. 22.4.1 The JavaPackage ClassA package in Java is collection of related Java classes. The JavaPackage class is a JavaScript data type that represents a Java package. The properties of a JavaPackage are the classes that the package contains (classes are represented by the JavaClass class, which we'll see shortly), as well as any other packages that the package contains. There is a restriction on the JavaPackage class: you cannot use a JavaScript for/in loop to obtain a complete list of all packages and classes that a JavaPackage contains. This restriction is the result of an underlying restriction in the Java virtual machine. All JavaPackage objects are contained within a parent JavaPackage; the Window property named Packages is a top-level JavaPackage that serves as the root of this package hierarchy. It has properties such as java, sun, and netscape, which are JavaPackage objects that represent the various hierarchies of Java classes that are available to the browser. For example, the JavaPackage Packages.java contains the JavaPackage Packages.java.awt. For convenience, every Window object also has java, sun, and netscape properties that are shortcuts to Packages.java, Packages.sun, and Packages.netscape. Thus, instead of typing Packages.java.awt, you can simply type java.awt. To continue with the example, java.awt is a JavaPackage object that contains JavaClass objects such as java.awt.Button, which represents the java.awt.Button class. But it also contains yet another JavaPackage object, java.awt.image, which represents the java.awt.image package in Java. As you can see, the property naming scheme for the JavaPackage hierarchy mirrors the naming scheme for Java packages. Note, however, that there is one big difference between the JavaPackage class and the actual Java packages that it represents. Packages in Java are collections of classes, not collections of other packages. That is, java.lang is the name of a Java package, but java is not. So the JavaPackage object named java does not actually represent a package in Java -- it is simply a convenient placeholder in the package hierarchy for other JavaPackage objects that do represent real Java packages. On most systems, Java classes are installed in files in a directory hierarchy that corresponds to their package names. For example, the java.lang.String class is stored in the file java/lang/String.class. Actually, this file is usually contained in a ZIP file, but the directory hierarchy is still there, encoded within the archive. Therefore, instead of thinking of a JavaPackage object as representing a Java package, you may find it clearer to think of it as representing a directory or subdirectory in the directory hierarchy of Java classes. The JavaPackage class has a few shortcomings. There is no way for LiveConnect to tell in advance whether a property of a JavaPackage refers to a Java class or to another Java package, so JavaScript assumes that it is a class and tries to load a class. Thus, when you use an expression like java.awt, LiveConnect first looks for a class file java/awt.class. It may even search for this class over the network, causing the web server to log a "404 File Not Found" error. If LiveConnect does not find a class, it assumes that the property refers to a package, but it has no way to ascertain that the package actually exists and has real classes in it. This causes the second shortcoming: if you misspell a class name, LiveConnect happily treats it as a package name, rather than telling you that the class you are trying to use does not exist. 22.4.2 The JavaClass ClassThe JavaClass class is a JavaScript data type that represents a Java class. A JavaClass object does not have any properties of its own -- all of its properties represent (and have the same name as) the public static fields and methods of the represented Java class. These public static fields and methods are sometimes called class fields and class methods, to indicate that they are associated with a class rather than an object instance. Unlike the JavaPackage class, JavaClass does allow the use of the for/in loop to enumerate its properties. Note that JavaClass objects do not have properties representing the instance fields and methods of a Java class -- individual instances of a Java class are represented by the JavaObject class, which is documented in the next section. As we saw earlier, JavaClass objects are contained in JavaPackage objects. For example, java.lang is a JavaPackage that contains a System property. Thus, java.lang.System is a JavaClass object, representing the Java class java.lang.System. This JavaClass object, in turn, has properties such as out and in that represent static fields of the java.lang.System class. You can use JavaScript to refer to any of the standard Java system classes in this same way. The java.lang.Double class is named java.lang.Double (or Packages.java.lang.Double), for example, and the java.awt.Button class is java.awt.Button. Another way to obtain a JavaClass object in JavaScript is to use the getClass( ) function. Given any JavaObject object, you can obtain a JavaClass object that represents the class of that Java object by passing the JavaObject to getClass( ).[3]
Once you have a JavaClass object, there are several things you can do with it. The JavaClass class implements the LiveConnect functionality that allows JavaScript programs to read and write the public static fields of Java classes and invoke the public static methods of Java classes. For example, java.lang.System is a JavaClass. We can read the value of a static field of java.lang.System like this: var java_console = java.lang.System.out; Similarly, we might invoke a static method of java.lang.System with a line like this one: var java_version = java.lang.System.getProperty("java.version"); Recall that Java is a typed language -- all fields and method arguments have types. If you attempt to set a field or pass an argument of the wrong type, an exception is thrown. (Or, in versions of JavaScript prior to 1.5, a JavaScript error occurs.) There is one more important feature of the JavaClass class. You can use JavaClass objects with the JavaScript new operator to create new instances of Java classes -- i.e., to create JavaObject objects. The syntax for doing so is just as it is in JavaScript (and just as it is in Java): var d = new java.lang.Double(1.23); Finally, having created a JavaObject in this way, we can return to the getClass( ) function and show an example of its use: var d = new java.lang.Double(1.23); // Create a JavaObject var d_class = getClass(d); // Obtain the JavaClass of the JavaObject if (d_class == java.lang.Double) ...; // This comparison will be true When working with standard system classes like this, you can typically use the name of the system class directly rather than calling getClass( ). The getClass( ) function is more useful in obtaining the class of a non-system object, such as an applet instance. Instead of referring to a JavaClass with a cumbersome expression like java.lang.Double, you can define a variable that serves as a shortcut: var Double = java.lang.Double; This mimics the Java import statement and can improve the efficiency of your program, since LiveConnect does not have to look up the lang property of java and the Double property of java.lang. 22.4.3 The JavaObject ClassThe JavaObject class is a JavaScript data type that represents a Java object. The JavaObject class is, in many ways, analogous to the JavaClass class. As with JavaClass, a JavaObject has no properties of its own -- all of its properties represent (and have the same names as) the public instance fields and public instance methods of the Java object it represents. As with JavaClass, you can use a JavaScript for/in loop to enumerate all the properties of a JavaObject object. The JavaObject class implements the LiveConnect functionality that allows us to read and write the public instance fields and invoke the public methods of a Java object. For example, if d is a JavaObject that represents an instance of the java.lang.Double class, we can invoke a method of that Java object with JavaScript code like this: n = d.doubleValue( ); Similarly, we saw earlier that the java.lang.System class has a static field out. This field refers to a Java object of class java.io.PrintStream. In JavaScript, we can refer to the corresponding JavaObject as: java.lang.System.out and we can invoke a method of this object like this:[4]
java.lang.System.out.println("Hello world!"); A JavaObject object also allows us to read and write the public instance fields of the Java object it represents. Neither the java.lang.Double class nor the java.io.PrintStream class used in the preceding examples has any public instance fields, however. But suppose we use JavaScript to create an instance of the java.awt.Rectangle class: r = new java.awt.Rectangle( ); Then we can read and write its public instance fields with JavaScript code like the following: r.x = r.y = 0; r.width = 4; r.height = 5; var perimeter = 2*r.width + 2*r.height; The beauty of LiveConnect is that it allows a Java object, r, to be used just as if it were a JavaScript object. Some caution is required, however: r is a JavaObject and does not behave identically to regular JavaScript objects. The differences will be detailed later. Also, remember that unlike JavaScript, the fields of Java objects and the arguments of their methods are typed. If you do not specify JavaScript values of the correct types, you cause JavaScript errors or exceptions. In Netscape 6.1 and later the JavaObject class makes methods available by name and by name plus argument type, which is useful when there are two or methods that share the same name but expect different types of arguments. As we saw earlier in this chapter, if a JavaObject o represents an object that has two methods named "convert", the convert property of o may refer to either of those methods. In recent versions of LiveConnect, however, o also defines properties that include the argument types, and you can specify which version of the method you want by including this type information: var iconvert = o["convert(int)"]; // Get the method we want iconvert(3); // Invoke it Because the name of the property includes parentheses, you can't use the regular "." notation to access it and must express it as a string within square brackets. The JavaClass type has the same capability for overridden static methods. 22.4.4 The JavaArray ClassThe final LiveConnect data type for JavaScript is the JavaArray class. As you might expect by now, instances of this class represent Java arrays and provide the LiveConnect functionality that allows JavaScript to read the elements of Java arrays. Like JavaScript arrays (and like Java arrays), a JavaArray object has a length property that specifies the number of elements it contains. The elements of a JavaArray object are read with the standard JavaScript [] array index operator. They can also be enumerated with a for/in loop. You can use JavaArray objects to access multidimensional arrays (actually arrays of arrays), just as in JavaScript or Java. For example, suppose we create an instance of the java.awt.Polygon class: p = new java.awt.Polygon( ); The JavaObject p has properties xpoints and ypoints that are JavaArray objects representing Java arrays of integers. (To learn the names and types of these properties, look up the documentation for java.awt.Polygon in a Java reference manual.) We can use these JavaArray objects to randomly initialize the Java polygon with code like this: for(var i = 0; i < p.xpoints.length; i++) p.xpoints[i] = Math.round(Math.random( )*100); for(var i = 0; i < p.ypoints.length; i++) p.ypoints[i] = Math.round(Math.random( )*100); 22.4.5 Java MethodsThe JavaClass and JavaObject classes allow us to invoke static methods and instance methods, respectively. In Netscape 3, Java methods were internally represented by a JavaMethod object. In Netscape 4, however, Java methods are simply native methods, like the methods of built-in JavaScript objects such as String and Date. When you're using Java methods, remember that they expect a fixed number of arguments of fixed types. If you pass the wrong number of arguments, or an argument of the wrong type, you cause a JavaScript error. |