LiveConnect Support in the Next Generation Java™ Plug-In Technology Introduced in Java SE 6 update 10

Table of Contents


Section 1. Introduction

LiveConnect is a feature of web browsers which allows Java applets to communicate with the JavaScript engine in the browser, and JavaScript on the web page to interact with applets. The LiveConnect concept originated in the Netscape web browser, and to this date, Mozilla and Firefox browsers have had the most complete support for LiveConnect features. It has, however, been possible to call between JavaScript and Java in some fashion on all web browsers for a number of years.

In the new Java Plug-In, the interoperability layer between the Java and JavaScript languages has been rewritten. In the Firefox family of browsers, all specialized knowledge of Java has been removed, and the Java Plug-In now operates like any other scriptable plug-in. The Java Plug-In now assumes responsiblity for the implementation of all of the LiveConnect features on all web browsers, yielding many benefits:

  • Improved reliability. Java/JavaScript calls may be made without concerns about destabilizing the web browser. Java/JavaScript behavior in corner cases, such as during applet termination, has been significantly improved.
  • Improved performance. Even though Java/JavaScript calls now cross an operating system process boundary, the new Java Plug-In is nearly always either as fast as or faster than the classic Java Plug-In on all browsers and platforms, and is in some cases dramatically faster. Based on performance tests, the new plug-in is never less than half the speed of the classic plug-in.
  • Better cross-browser portability. JavaScript code calling Java, and vice versa, is now much more portable when moving from one browser family to another.
  • Increased functionality. Formerly Mozilla-specific LiveConnect functionality, such as the ability to call static Java methods, instantiate new Java objects and reference third-party packages from JavaScript, is now available in all browsers.

This specification both documents the behavior of the Java/JavaScript bridge in the new Java Plug-In, and specifies how alternate implementations of a Java Plug-In should behave to support portability of mixed Java/JavaScript code. It supersedes all previous LiveConnect specifications.

Section 2. Calling from JavaScript to Java

JavaScript on a web page can interact with Java applets embedded on the page. You can call methods on Java objects, get and set fields in Java objects, get and set Java array elements, create new instances of Java objects, and more. The following sections describe all of the supported operations and how values are passed back and forth between the JavaScript engine in the browser and the Java virtual machine.

2.1 Supported Operations

2.1.1 Invoking Instance Methods

JavaScript can call any public method of any public Java class. The "root", or first, Java object exposed to the JavaScript engine for a given applet is the applet itself, an instance of java.lang.Applet. If you call a Java method which returns an object, that object will be exposed to the JavaScript engine, and you can call its public methods as well.

Examples

  • Java code:
    
        public class MethodInvocation extends Applet {
            public void noArgMethod() { ... }
            public void someMethod(String arg) { ... }
            public void someMethod(int arg) { ... }
            public int  methodReturningInt() { return 5; }
            public String methodReturningString() { return "Hello"; }
            public OtherClass methodReturningObject() { return new OtherClass(); }
        }
    
        public class OtherClass {
            public void anotherMethod();
        }
    
  • Web page and JavaScript code:
    
        <applet id="app"
                archive="examples.jar"
                code="MethodInvocation" ...>
        </applet>
        <script language="javascript">
            app.noArgMethod();
            app.someMethod("Hello");
            app.someMethod(5);
            var five = app.methodReturningInt();
            var hello = app.methodReturningString();
            app.methodReturningObject().anotherMethod();
        </script>
    
  • Executable Test Case
  • Complete Source Code (MethodInvocation.html / .java)

2.1.2 Accessing Instance Fields

JavaScript can access any public field of any public Java class, and can both set and get fields of Java objects.

Examples

  • Java code:
    
        public class FieldAccess extends Applet {
            public int intField = 5;
            public String stringField = "Hello";
            public OtherClass otherField = new OtherClass();
        }
    
        public class OtherClass {
            public int intField = 6;
            public String stringField = "Testing";
        }
    
  • Web page and JavaScript code:
    
        <applet id="app"
                archive="examples.jar"
                code="FieldAccess" ...>
        </applet>
        <script language="javascript">
            var val = app.intField;
            app.intField = 6;
            val = app.stringField;
            app.stringField = "Goodbye";
            val = app.otherField.intField;
            app.otherField.intField = 7;
            val = app.otherField.stringField;
            app.otherField.stringField = "1, 2, 3";
        </script>
    
  • Executable Test Case
  • Complete Source Code (FieldAccess.html / .java)

2.1.3 Accessing Array Elements and Passing Arrays as Arguments

JavaScript code can access and modify Java arrays. Java arrays that are passed or returned to JavaScript code appear like ordinary JavaScript arrays: they have a "length" field and can be accessed using normal JavaScript array indexing syntax. They are passed from the Java virtual machine to the JavaScript engine by reference, meaning that any changes made by JavaScript code are visible to Java code referencing the same array.

Such arrays accessible from JavaScript still retain Java array semantics. Elements can not be added beyond the end of the array, nor can individual array elements be deleted. Attempts to perform these operations will raise an exception in the JavaScript engine.

JavaScript code can also pass arrays to Java code. If a Java method takes an array type as argument, JavaScript may pass a JavaScript array object or literal for that argument. The Java Plug-In will allocate a new Java array and convert each element of the JavaScript array to the appropriate Java type using the conversion rules described in the section on JavaScript-to-Java data type conversions below. Multidimensional arrays are supported, as are sparse JavaScript arrays: if an array element is not defined in the JavaScript array, the default value (0 for a primitive value or null for an object value) will be used during construction of the Java array. Note that because the array data is necessarily copied, changes made to these arrays by Java code will not be reflected in the JavaScript engine.

Examples

  • Java code:
    
        public class ArrayAccess extends Applet {
            public int[] methodReturning123() { return new int[] { 1, 2, 3 } }
            public void  methodExpecting123(int[] arg) { ... }
        }
    
  • Web page and JavaScript code:
    
        <applet id="app"
                archive="examples.jar"
                code="ArrayAccess" ...>
        </applet>
        <script language="javascript">
            var arr = app.returns123();
            swapElements0And2(arr);
            app.expects321(arr);
            app.expects321([ 3, 2, 1 ]);
            // Returns 2-dimensional Java array
            arr = app.returns1Through9();
            // Transform this into 9..1
            swapElements0And2(arr);
            swapColumns0And2(arr);
            app.expects9Through1(arr);
            app.expects9Through1([[9, 8, 7], [6, 5, 4], [3, 2, 1]]);
        </script>
    
  • Executable Test Case
  • Complete Source Code (ArrayAccess.html / .java)

2.1.4 The Per-Applet Packages Keyword

In the new Java Plug-In, there is a synthetic Packages keyword attached to the applet object which provides access to the Java packages visible to that applet. Using this keyword, JavaScript code can:

  • Invoke static methods of Java classes
  • Set and get static fields of Java classes
  • Create new instances of Java objects

Using the per-applet Packages keyword, JavaScript code can even access user-defined classes, giving the browser the ability to perform fine-grained scripting of Java applications.

Examples

  • Java code:
    
        package com.mycompany;
    
        public class PackageAccess extends Applet {
        }
    
        public class MyClass {
            public static int staticField = 5;
            public static void staticMethod() { ... }
            public void instanceMethod() { ... }
        }
    
  • Web page and JavaScript code:
    
        <applet id="app"
                archive="examples.jar"
                code="com.mycompany.PackageAccess" ...>
        </applet>
        <script language="javascript">
            var val = app.Packages.com.mycompany.MyClass.staticField;
            app.Packages.com.mycompany.MyClass.staticField = 6;
            app.Packages.com.mycompany.MyClass.staticMethod();
            val = new app.Packages.com.mycompany.MyClass();
            val.instanceMethod();
        </script>
    
  • Executable Test Case
  • Complete Source Code (PackageAccess.html / .java)

2.1.5 Deprecated Functionality: the Global Packages, java and netscape Keywords

The Mozilla family of browsers has historically provided support for access to the Java language from JavaScript even on web pages that don't contain Java applets. In this browser family, there are global java, netscape and Packages keywords available to JavaScript code which allow calling static methods, accessing static fields, and creating new instances of Java classes in similar fashion to the per-applet Packages keyword above.

The semantics of these keywords becomes problematic when more than one applet is available on the web page. If you want to access one particular applet's user-defined classes (for example, in a com.mycompany package), how would the global Packages keyword know which applet to refer to? The new Java Plug-In also supports attaching more than one Java virtual machine instance to the web browser for executing applets. The semantics of these global keywords becomes even more complicated in this situation.

For this reason, the global java, netscape and Packages JavaScript keywords are deprecated. They continue to function in the Firefox browser, but it is strongly recommended to transition existing code using them to use the new per-applet Packages keyword. It is not possible to access user-defined classes using these global keywords; attempts to do so will yield undefined results.

2.2 Overloaded Method Resolution

The Java language supports method overloading, where multiple methods may have the same name, but different sets of argument types. At a particular call site, the Java compiler (javac) determines which version of the method is being called based on the number and types of the arguments. If it is not possible to determine unambiguously which version of the method is being targeted, javac reports an error and fails to compile the calling code.

When JavaScript code calls an overloaded Java method, it is necessary to determine which variant of the method should be invoked at run time rather than compile time, based on the number and types of the values being passed to the method from the JavaScript engine. The Java Plug-In is responsible for this overloaded method resolution rather than the Java compiler, because it is necessary to do this work dynamically.

The Java Plug-In currently uses a cost-based algorithm to determine which overloaded variant of a method should be invoked. The cost of invoking a particular overloaded variant is computed as the sum of the conversion costs for each of the incoming arguments to the types required in the method's signature. The lowest cost method is then invoked. When two methods have the same cost, an exception is raised in the JavaScript engine indicating that the invocation was ambiguous.

The supported set of built-in conversions when passing values from the JavaScript engine to Java is discussed in the next section on data type conversions.

The exact values for various conversion costs for are deliberately left unspecified at the present time, to prevent over-dependence of applications on the overload resolution algorithm. The intent is that when it is obvious from examination of the incoming arguments which overloaded variant should be invoked, the cost-based algorithm should not report ambiguities. However, as a hint to developers, the following rules are currently followed:

  • The following conversions have the lowest cost:
    • Numeric type to the analogous Java primitive type
    • Null to any non-primitive type
    • JSObject to JSObject
    • Class type to Class type where the types are equal
  • The following conversions report higher cost:
    • Numeric type to a different primitive type
    • String to numeric type
    • Class type to superclass type; this assists in overload resolution where one method takes a subclass as argument and another method takes a superclass as argument, and an instance of the subclass is passed in. The Java Plug-In computes a measure of the "distance" in the class hierarchy between a value and the desired type.
  • The following conversion reports still higher cost:
    • Any Java value to String
  • The following conversions report even higher cost:
    • JSObject to String
    • JSObject to Java array
  • The following are reported as not convertible (negative conversion cost):
    • Any value to a type not represented by java.lang.Class
    • Null to primitive type
    • JSObject to any type not described above
    • Any other conversion not described above

It is anticipated that the algorithm for overloaded method resolution will need to change over time, but it is hoped that the current implementation will allow for the development of sophisticated applications. Your feedback is appreciated on improving the algorithm, especially test cases for situations where the algorithm fails.

2.3 Data Type Conversions

When calling a Java method from JavaScript, setting a Java field, or passing arguments to a constructor of a Java class, one or more values are passed from the JavaScript engine to Java. Because JavaScript is a dynamically typed language, while Java is statically typed, it is necessary to convert the incoming values from the JavaScript engine to the appropriate data types required by the Java virtual machine. The following tables describe the supported data type conversions when passing values from JavaScript to Java. Attempts to perform conversions not described in these tables will raise an exception in the JavaScript engine.

Return values from Java-to-JavaScript invocations, such as call and eval against netscape.javascript.JSObject, are also subject to the same conversion rules. These return values are always converted to java.lang.Object.

2.3.1 Number Values

Various vendors' JavaScript engines represent numeric values in different ways. For example, some JavaScript engines represent all numeric values natively as double-precision floating-point values, while some JavaScript engines can represent other kinds of numbers, such as integer numbers, natively.

This specification makes no guarantees about the representation of numeric values in the JavaScript engine. Before the conversions below are applied, it is assumed that the JavaScript value has been transferred in to the Java virtual machine using the closest available representation, such as int or double.

Java parameter type Conversion rules
byte
char
short
int
long
float
double
  • Values are converted using Java casts, the semantics of which are defined by the Java language specification. As mentioned above, the representation of the source value coming in from the JavaScript engine is not specified.
  • Narrowing conversions are supported, unlike in Java reflection.
java.lang.Byte
java.lang.Character
java.lang.Short
java.lang.Integer
java.lang.Long
java.lang.Float
java.lang.Double
java.lang.Object
  • Values are converted per the rules for primitive values and then boxed in the appropriate Java boxing object.
  • When converting a JavaScript number value to java.lang.Object, the boxing object most closely matching the representation of the JavaScript value will be used. The only guarantee in these conversions is that the result will be an instance of java.lang.Number.
java.lang.String
  • Values are converted to strings. For example: 237 becomes "237"

Because different JavaScript engines use different internal representations for numbers, there is no guarantee about the precise format of the Java string. However, implementations should make a best effort to use the closest reasonable format. For example, if the JavaScript engine uses an integer representation for the number 237, the Java string should read "237" rather than, for example, "237.0".

Use the equals() method, rather than the == operator, to compare these converted strings with other string values.

boolean
  • 0 and NaN values are converted to false.
  • Other values are converted to true.

2.3.2 Boolean Values

When JavaScript boolean values are passed as parameters to Java methods, they are converted according to the following rules.

Java parameter type Conversion rules
boolean All values are converted directly to the Java equivalents.
java.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. true becomes "true"; false becomes "false". Use the equals() method, rather than the == operator, to compare these converted strings with other string values.
byte
char
short
int
long
float
double
true becomes 1; false becomes 0.

2.3.3 String Values

When JavaScript strings are passed as parameters to Java methods, they are converted according to the following rules.

Java parameter type Conversion rules
java.lang.String
java.lang.Object
A new instance of java.lang.String is created which contains the Unicode characters of the JavaScript string.
byte
short
int
long
float
double
The valueOf method of the appropriate Java boxing type (e.g., java.lang.Byte.valueOf(), java.lang.Short.valueOf()) is called to convert the string to the primitive value.
char The method java.lang.Short.decode() is used to convert the String to a primitive short value, and from there is cast to a primitive char value.
boolean The empty string becomes false. All other values become true.

2.3.4 Array Values

When a JavaScript array is passed to as a parameter to a Java method, it is converted according to the following rules.

Java parameter type Conversion rules
One-dimensional array type:
byte[]
short[]
char[]
int[]
long[]
float[]
double[]
Object type array (Object[], String[], etc.)
A new Java array is allocated and each element of the JavaScript array is converted to the appropriate type using the conversion rules described in this section. If the JavaScript array is sparse, meaning that some of its elements are undefined, those values are converted as 0 for primitive values and null for object values. If a value of the JavaScript array is not convertible according to the rules in this section, an exception is raised in the JavaScript engine.
Multi-dimensional array type
(int[][], String[][], etc.)
A new Java array is allocated and each element is converted according to the rules described in this section, including this rule and the base case for one-dimensional arrays.
java.lang.String The JavaScript array is converted to a string representation according to the rules of the JavaScript engine. Use the equals() method, rather than the == operator, to compare these converted strings with other string values.

2.3.5 Other JavaScript Objects

Any other JavaScript object which is passed to Java is converted according to the following rules.

Java parameter type Conversion rules
netscape.javascript.JSObject A reference to the JavaScript object is passed to Java.
java.lang.String The toString method is called on the object, and the result is returned as a new String instance.

2.3.6 Java Objects

When a Java object which was previously returned to the JavaScript engine is passed back to Java, the object is simply checked for assignment compatibility with the target type. The only exception to this rule is automatic conversion to java.lang.String.

Java parameter type Conversion rules
Any class or interface type which is assignment-compatible with the object. The original object is passed back to Java.
java.lang.String The toString method is called on the original object, and the result is returned as a new String instance.

2.3.7 Null and Undefined Values

When the JavaScript null or undefined value is passed as a parameter to a Java method, it is converted according to the following rules.

Java parameter type Conversion rules
Any class
Any interface type
The value becomes null.
byte
char
short
int
long
float
double
The value becomes 0.
boolean The value becomes false.

2.4 Java Object Operations and the Applet Lifecycle

The first JavaScript-to-Java call is allowed against a particular applet instance when either:

  • Applet.init() completes for that particular applet instance, or
  • the applet makes its first Java-to-JavaScript call.

The Java Plug-In guarantees that if the browser attempts to make a JavaScript-to-Java call against a particular applet, the browser will wait, with control not returning to the JavaScript engine, until one of the following occurs:

  1. Applet.init() completes for that particular applet instance
  2. The applet makes its first Java-to-JavaScript call
  3. An error occurs during initialization of the applet

For cases (1) and (2) above, once either of these conditions is satisfied, all subsequent JavaScript-to-Java calls go through immediately for that applet instance. For case (3), an exception will be raised in the JavaScript engine for the initial and any subsequent JavaScript-to-Java calls against that applet instance.

2.5 Threading Model

By default, when a JavaScript-to-Java call is made against a particular applet or an object returned from a prior call against a particular applet, the call will be handled on the Java side by a worker thread associated with that applet. The worker thread is guaranteed to be distinct from all threads created by user code, and only one worker thread per applet is created.

If an applet makes a Java-to-JavaScript call, and as a result a JavaScript-to-Java call is made, that call will be performed on the thread which made the Java-to-JavaScript call. This is called the round-trip scenario. The round-trip JavaScript-to-Java call is made in response to the downcall from Java to JavaScript, so the initiating thread is the one that should handle the upcall.

The JavaScript engines in all of today's web browsers are conceptually single threaded with respect to the web page. The Java language, however, is inherently multithreaded. If multiple Java threads attempt to call into the JavaScript engine, only one will be allowed through at any given time. The rest of the threads will wait for one of two situations to occur: either the initial Java-to-JavaScript call completes, or a JavaScript-to-Java call is made. In either of these occurrences, the JavaScript engine once again becomes "available" for Java-to-JavaScript calls. If multiple Java threads were attempting to make concurrent calls to the JavaScript engine, an arbitrary one will be selected for its call to proceed.

These multithreading rules ensure that the JavaScript engine is accessed only in the required single-threaded fashion. However, user code must still perform appropriate synchronization in multithreaded situations in order to achieve desired results.

2.6 Lifetime of Java Objects Accessed from JavaScript

All Java objects returned to the web browser are scoped within a particular applet instance. The applet itself is the initial object exposed to the JavaScript engine. Calls against that applet object (including against the per-applet Packages keyword) may return other Java objects to the JavaScript engine. These objects are associated with the applet instance that returned them, as are any subsequent objects that might be returned from method invocations, field fetches, etc. against them.

Normally, a reference held by the JavaScript engine to a Java object acts as a persistent reference, preventing that object from being garbage collected in the hosting JVM. After the JavaScript engine drops the reference, the JavaScript engine's garbage collector will run, and eventually cause the persistent reference to the target Java object to be dropped and later reclaimed by the JVM's garbage collector once it is no longer reachable.

However, if a particular applet on a web page is destroyed, for example by removing it from the HTML Document Object Model or by switching to another web page, any references the JavaScript engine may still hold to Java objects scoped within that applet instance are immediately invalidated. The associated Java objects immediately become eligible for garbage collection (assuming no other persistent references exist to those objects), and further attempts to operate upon the JavaScript references to those objects will raise exceptions in the JavaScript engine.

2.7 Multiple JVM Support

The new Java Plug-In supports multiple simultaneous JVM instances attached to the web browser. Two applets hosted on the same web page might actually be running in two separate JVMs. How does this affect the interaction with the JavaScript engine in the web browser?

Perhaps surprisingly, hardly at all. JavaScript on the web page can interact identically with any applet, regardless of which JVM instance it is running in. Java objects may be fetched from one applet using JavaScript and passed in to another applet. There is only one additional rule imposed:

When passing a Java object to a particular JVM instance (as a method parameter, field value, etc.), that object must have originated in that JVM instance.

There is no support for serialization of objects between JVM instances; if an attempt is made to pass an object into a different JVM instance from where it originated, an exception will be raised in the JavaScript engine.

2.8 Security Model of JavaScript-to-Java Calls

The Java platform's security architecture provides the concept of a secure sandbox. Code which is not both signed and trusted runs with a restricted set of permissions. In particular, Java bytecode downloaded from the Internet may not access the local file system directly, and may only connect back to the network host from where the code originated. These restrictions ensure that unknown code may not violate the user's privacy, nor use the user's computer to perform denial-of-service attacks against arbitrary network hosts.

When an operation is attempted which requires certain permissions, such as making a network connection, the Java platform's SecurityManager enumerates all of the code running on the current thread. This might include both trusted and untrusted code, in particular untrusted code from multiple origins. It takes the intersection of the permission sets associated with all of the currently-running code. This minimal intersection represents the allowed permissions at the current time, and this is compared against the permissions needed to perform the operation. If the current permissions satisfy those needed to perform the operation, it proceeds; otherwise, a SecurityException is raised.

In the absence of LiveConnect, an untrusted applet may connect back to the host from which its code originated (typically the codebase, although absolute URLs are allowed in the archive parameter), as described above. When JavaScript code on the web page calls into the applet to perform an operation on its behalf, however, additional security measures must be enforced. Otherwise, an arbitrary web page could re-use an applet hosted on a given site and use the applet to make network connections back to that site.

Earlier versions of the Java Plug-In modeled the security of JavaScript-to-Java calls slightly differently on different browsers, because of differences in how the Java virtual machine was hooked in to the web browser, and differences in whether the browser or the Java Plug-In was responsible for enforcing certain aspects of the security model. With the introduction of the new Java Plug-In, the behavior across browsers has been unified, and is summarized as follows:

  • JavaScript code on the web page may always make JavaScript-to-Java calls against an applet on the page. (The MAYSCRIPT attribute is no longer necessary.)
  • When a JavaScript-to-Java call is made, the JavaScript code is modeled as though it were coming from an untrusted applet whose code origin is the document base (i.e., the URL of the directory containing the document).

The statements above are very simple, but have some subtle consequences.

  • If the HTML document and the applet both originate from the same site, then JavaScript on the web page may cause network connections to be made back to the originating host on its behalf.
  • If the HTML document and the applet originate from different sites, then JavaScript on the web page may not cause any network connections to be made on its behalf.
  • The concept of "signed JavaScript", which was a Mozilla-specific feature not in widespread use, is no longer supported. It is not possible to grant elevated permissions to JavaScript code. Developers should be careful to not expose APIs in their applets which would accidentally confer additional privileges on untrusted JavaScript code by using AccessController.doPrivileged indiscriminately. Developers who must grant elevated privileges to JavaScript code are encouraged to serve their applets over verifiable HTTPS connections, and perform checks to ensure that the document base of the web page hosting the applet is the same as the expected origin of the applet's code.
  • Though a web page may contain JavaScript code from multiple sites, the Java Plug-In has no visibility into the origin of each individual piece of JavaScript code. It is the responsibility of the web page developer to ensure that he or she does not import JavaScript code from untrusted sites which might attempt to make undesired calls against applets running on the web page.

The new LiveConnect security model behaves identically across browsers and is significantly easier to understand and explain than the previous unspecified behavior. Tests with real-world applications indicate that the new security model is highly backward compatible. Your feedback is appreciated, especially if you encounter compatibility issues with the new security model.

Section 3. Calling from Java to JavaScript

A Java applet can interact with its surrounding web page and the JavaScript engine in the web browser. Java code can call JavaScript functions, get, set and remove fields of JavaScript objects, get and set elements of JavaScript arrays, and evaluate snippets of JavaScript code. Through either the JavaScript DOM APIs or the Java Common DOM APIs, the Java applet can modify the web page dynamically, adding, removing and moving HTML elements. The following sections describe all of the supported operations and how values are passed back and forth between the Java virtual machine and the JavaScript engine in the web browser.

3.1 The netscape.javascript.JSObject Class

All instances of JavaScript objects appear within Java code as instances of netscape.javascript.JSObject. When you call a method in your Java code from JavaScript, you can pass it a JavaScript object as an argument. To do this, you must define the corresponding formal parameter of the method to be of type JSObject.

Alternatively, a Java applet can bootstrap Java-to-JavaScript communication by calling the static getWindow method on the JSObject class, passing the applet instance as an argument. This method fetches a reference to the JavaScript window object containing the applet, which can be used for subsequent evaluation, function calls, fetches of variables, etc.

When 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.

Examples

  • Java code:
    
        public class JavaJSTest extends Applet {
            public void start() {
                JSObject window = JSObject.getWindow(this);
                // Test function calls
                String str = (String) window.eval("getString();");
                if (!str.equals("Hello, world!")) {
                    throw new RuntimeException(); // test failed
                }
                Number num = (Number) window.eval("getNumber()");
                if (num.intValue() != 5) {
                    throw new RuntimeException(); // test failed
                }
                // Test field access
                JSObject res = (JSObject) window.eval("new cities();");
                if (!((String) res.getMember("b")).equals("Belgrade")) {
                    throw new RuntimeException(); // test failed
                }
                res.setMember("b", "Belfast");
                if (!res.getMember("b").equals("Belfast")) {
                    throw new RuntimeException(); // test failed
                }
                res.removeMember("b");
                try {
                    res.getMember("b");
                    throw new RuntimeException(); // test failed
                } catch (JSException e) {
                    // Member should not be present any more
                }
                // Test array access
                res = (JSObject) window.eval("getTestArray();");
                if (!((String) res.getSlot(0)).equals("foo") ||
                    !((String) res.getSlot(1)).equals("bar")) {
                    throw new RuntimeException(); // test failed
                }
                res.setSlot(1, "baz");
                if (!((String) res.getSlot(1)).equals("baz")) {
                    throw new RuntimeException(); // test failed
                }
                res.setSlot(2, "qux"); // Define new array element
                if (!((String) res.getSlot(2)).equals("qux")) {
                    throw new RuntimeException(); // test failed
                }
            }
        }
    
    
  • Web page and JavaScript code:
    
        <applet id="app"
                archive="examples.jar"
                code="JavaJSTest" ...>
        </applet>
        <script language="javascript">
            // Return a string value to Java
            function getString() {
              return "Hello, world!";
            }
            
            function getNumber() {
              return 5;
            }
            
            // Make an object with city names and an index letter.
            function cities() {
              this.a = "Athens";
              this.b = "Belgrade";
              this.c = "Cairo";
            }
            
            function getTestArray() {
              return [ "foo", "bar" ];
            }
        </script>
    
  • Executable Test Case
  • Complete Source Code (JavaJSTest.html / .java)

Note that the new Java Plug-In utilizes only the basic functionality of the JSException class, in particular its detail message and stack trace. Avoid using the functionality of throwing a particular object from JavaScript and having that object be available in the Java-side JSException, as this functionality is not portable between web browsers.

3.2 Compiling Java Code which Calls JavaScript

In order to call JavaScript, Java code uses the netscape.javascript.JSObject and netscape.javascript.JSException classes. Since the release of Java 2, Standard Edition version 1.4, these classes are provided in the jar file jre/lib/plugin.jar within either the Java Development Kit or Java Runtime Environment. If you reference these JavaScript classes, you will need to add plugin.jar to your compilation classpath. This can be done through your Java IDE, if you use one, or by passing the -classpath command-line argument to the Java compiler javac.

At run-time, the Java Plug-In automatically makes these classes available to applets, so no changes to the applet or how it is set up are necessary.

3.3 Data Type Conversions

Values passed from Java to JavaScript are converted as follows:

  • Boxing objects for Java numeric values (the java.lang classes Byte, Character, Short, Int, Long, Float, and Double) are unboxed and converted to the closest available JavaScript numeric type, except when they are the declared return type from a method or the result of a new expression using the per-applet Packages keyword. In this case, the boxing object will be returned to the JavaScript engine as a Java object.
  • A Java Boolean is converted to a JavaScript boolean, except when it is the declared return type from a method or the result of a new expression using the per-applet Packages keyword. In this case, the boxing object will be returned to the JavaScript engine as a Java object.
  • Java Strings are converted to JavaScript strings, except when they are the result of a new expression using the per-applet Packages keyword. In this case, the Java String is returned to the JavaScript engine as a Java object.
  • 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 much like a JavaScript Array object; you can set and get elements 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.

3.4 Javadoc

The official javadoc for the netscape.javascript package can be found here:

Section 4. Calling Non-Java Languages from JavaScript

The Java platform and virtual machine implementation host dozens, if not hundreds, of non-Java programming language implementations. JRuby, Jython, Groovy, Scala, and JavaFX Script are only a few of the better known languages which target the JVM. This Wikipedia article provides many other examples.

It is a desired goal to be able to write graphical Java programs in any language and embed them in an applet container so they can be viewed on a web page. This is already possible, and some programming language implementations provide support for this functionality today.

It is also desirable to be able to affect the behavior of these non-Java applets using JavaScript in the web browser. One can imagine "mapping" JavaScript syntax on to a particular JVM-based language to enable method calls, field access, and other operations. The difficulty is that most non-Java languages hosted on the JVM use name mangling, alternate representations of data types, and other schemes that do not work well with the default object access and data type conversion rules laid out in this specification.

To enable scripting of non-Java applets, the new Java Plug-In introduces an inter-language LiveConnect bridge. Run-time systems for languages hosted on the JVM can register delegates with this bridge that allow objects from those languages to be accessed using simple JavaScript syntax. The language implementor can make all of the decisions about how method invocation and field accesses work against objects in their language (subject to the browser's rules of JavaScript syntax), and also how values are converted back and forth between the JavaScript engine and their language. The bridge has been designed to support interaction with multiple languages simultaneously, so parts of the application can be written in one language, and other parts in another; JavaScript code on the web page can interact with both.

The Javadoc for the inter-language LiveConnect bridge is linked from the next section. The first language implementation taking advantage of this bridge is JavaFX Script. When a JavaFX applet is run with the new Java Plug-In, JavaScript on the web page may interact with the main script, descend into the scene graph, call JavaFX Script functions, and more. The JavaFX compiler runtime is responsible for mapping JavaScript field accesses and other operations into JavaFX Script.

4.1 Javadoc

The Javadoc for the Inter-Language LiveConnect Bridge can be found here:

Section 5. Conformance Tests

Conformance tests for this specification are a work in progress. Sun Microsystems, Inc. hopes that the community will assist in writing test cases that ensure that implementations of Java Plug-In technology allow interoperability between JavaScript and Java content across a wide range of platforms, web browsers and hardware devices. The following set of tests, which was originally developed by the Netscape corporation, verifies some basic functionality of the new Java Plug-In's LiveConnect implementation. It should not be considered a comprehensive conformance test suite. Note that this test suite requires the new Java Plug-In and does not work with earlier versions of the Java Plug-In.

Section 6. Acknowledgments

We thank Mozilla for allowing us to use the LiveConnect Overview from the Core JavaScript 1.5 Guide and the early LiveConnect conformance tests as reference material for this specification, and for the collaboration which allowed the new Java Plug-In to work with full functionality on Firefox 3.

Section 7. Feedback

If you find an area of this specification that needs clarification or correction, please report it using the Sun Bug Reporter. Please first query the Sun Bug Database under Category Java Plugin, Subcategory plugin2 to see whether the bug has been reported already. When filing a bug, please use the Product/Category Java Plug-in, Subcategory plugin2. When reporting a bug in the LiveConnect implementation or an area where the behavior does not match the specification, please provide the following information:

  • Operating system name and version
  • Web Browser name and version
  • A self-contained test case
  • Clear instructions on how to reproduce the failure
  • What the failure mode is (i.e., expected and actual behavior)

Thank you for helping to improve the reliability and portability of the new LiveConnect implementation.