LiveConnect – The glue between Java and JavaScript

Did you know Java-to-JavaScript interaction is possible? This is known as LiveConnect. LiveConnect makes it possible to use Java for things not otherwise possible in browser environments, while still keeping display logic in the web page in HTML/JavaScript.

LiveConnect is in most cases straightforward. Two examples:

document.getElementById('applet').uploadFile();

Above the JavaScript code calls the java uploadFile method.

import netscape.javascript.JSObject;
public class Applet{
  public void init(){
  JSObject.getWindow(this).eval("alert('applet:init')");
  // alternative way
  // (JSOBject)(JSObject.getWindow(this).getMember('alert')).call('applet:init');
  }
}

Above the Applet upon initialization calls JavaScript alert. JSObject is located in $JAVA_HOME/jre/lib/plugin.jar on Linux/Windows, which must be included on the classpath when compiling.

The least common denominator for Cross-browser LiveConnect support

LiveConnect has been around for ages (since Netscape Navigator 3.0 and IE4); however, some browsers do still not fully support LiveConnect! The table underneath gives an overview of LiveConnect support in major browsers and OSes. The table is based on a LiveConnect feature test. The test is available at jdams.org where you can test your own browser. In the table (J) means Java-to-JavaScript, and (JS) means JavaScript-to-Java.


Linux Mac Windows
Test /  Browser Chrome Firefox 3.6 Opera 9.8 Chrome Firefox 3.6 Safari 5 Chrome Firefox 3.6 IE 6 Safari 5
Mayscript param not required









JSObject != null









(J) getMember









(J) setMember









(J) getMember nested object call fct on it









(J) call null args









(J) call empty args









(J) call prim. arg









(J) call java object arg









(J) call with prim. return value









(J) call with obj. return value









(J) call with eval









(J) call with eval return value









(JS) get prim. java member









(JS) Java Strings are converted to JavaScript strings









(JS) get object java member









The tests show that applets using LiveConnect must avoid parsing complex objects back and forth and using call. If complex objects are needed they should be converted to a JSON string or similar before returning them to JavaScript from Java or vice versa. Luckily, the call method is superfluous since eval is available and working.

Plugin2: Maybe someday it gets easier

Java Plugin 2 (introduced in 1.6_10) solves many of the issues above. Only problem: Plugin2 is not available on the Mac! Until then or until all browser vendors fix the bugs, we have to stick with the lowest common denominator working feature set.

Signed applets

Applets, like all other client-code in browsers, is running under restrictions of the browser security model (Browser Security Handbook, part 2). For example, applets can’t access the file system, or make requests to cross-domains. That is, unless the applet is signed.

LiveConnect, however, degrades the security status of signed applet to unsigned. This is because unsigned code (JavaScript) interacts with signed code (Java). Fortunately, it is possible to elevate the privileges again:


try {
    AccessController.doPrivileged(new PrivilegedExceptionAction() {
        public Object run() throws Exception {
            // do stuff
            return null;
        }
    });
} catch (PrivilegedActionException e) {
    Exception ex = e.getException();
    // ...
}

Deploying Applets

Goto live-connect-test for different deployment examples</p>

There are numerous different applet deployment tags: the applet tag; the Mozilla-only embed tag; or the object tag. The applet tag was deprecated in HTML4.01 (spec) in favor for the generic object inclusion tag object.

Oracle claims that Applets deployed with object is not widely supported (Java plug-in developer guide). This is, however, not the case for modern browsers. The only tag needed to deploy applets is object!

Three parameters are essential for the object tag:

  • archive: space separated list of jar files;
  • code: fully qualified name of the aplet class; and
  • codebase: base URI for archive and code.

In addition, three attributes are essential:

  • type (required): must be the mimetype of applets, i.d., application/x-java-applet
  • width and height: specifies the display size of the applet.

With these things in mind, there are two deployment options for deploying applets with static HTML:

<!-- with class files located individually under the applet directory. -->
<object type="application/x-java-applet">
  <param name="codebase"  value="/applet" />
  <param name="code"      value="AppletTest" />
  <param name="mayscript" value="true" />
</applet>
<!-- with class files jarred. -->
<object type="application/x-java-applet" >
  <param name="code"      value="AppletTest" />
  <param name="archive"   value="/applet.jar" />
  <param name="mayscript" value="true" />
</object>

Dependencies to third-party libraries are specified either in the archive parameter or in the manifest of the JARed applet, e.g.,

Manifest-Version: 1.0
Class-Path: lib.jar lib2.jar

Third-party JARs are resolved relative to the URI of the JAR referencing them. In this case that means all JAR files (lib.jar and lib2.jar) must be located in the same directory as the applet jar.

Deployment caveats

  • The mayscript parameter must be present in Firefox Mac since LiveConnect otherwise is disabled.
  • On Firefox Mac LiveConnect is initialized when your make the first reference to any applet, e.g., by document.getElementById('appid'). An unfortunate side effect of that is the following: If the applet is included in the page via plain HTML, references to JSObject in the applet are initially null! The easy fix is to always inject the applet into the DOM via a script.
  • In Chrome if the size of the applet is set to zero (width="0" height="0") the applet is not loaded (bug).
  • Chrome issues an superfluous erroneous request for the Java class specified via the code parameter (bug).

Taking the caveats into consideration makes the cross-browser LiveConnect and HTML valid approach to deploy applets the following:

  
<script>
  document.getElementById('someid').innerHTML += [
  '<object type="application/x-java-applet" width="1" height="1">',
    '<param name="code" value="AppletTest"></param>',
    '<param name="archive" value="/applet.jar"></param>',
    '<param name="id" value="1"></param>',
  '</object>'].join('\n');
</script>

During development I recommend bypassing all the caching mechanisms by adding a time stamp to the jar URL. The deployment code then becomes:

<script>
  document.getElementById('someid').innerHTML += [
  '<object type="application/x-java-applet" width="1" height="1">',
    '<param name="code" value="AppletTest"></param>',
    '<param name="archive" value="/applet.jar?v=' + new Date().getTime() + '"></param>',
    '<param name="id" value="1"></param>',
  '</object>'].join('\n');
</script>

Note: Deployment is also possible with a script from oracle: deployJava.js. Two things are suboptimal with deployJava.js

  • it uses document.write to write applet tags to the DOM. That makes it impossible to lazy load the applet; and,
  • it injects the applet into the DOM with the deprecated applet tag.