RSS

Javascript Native Interface – JSNI

07 Oct

JSNI ?

Sometimes when you’re writing Java code (especially if you’re doing systems programming) you find that you have to get closer to the metal and run code outside the Java virtual machine. For example, you might need to access a code library that’s in a different language. To do that in Java, you would declare a method as native and then provide the implementation of that method in another language, such as C. This is called the Java Native Interface (JNI). You can do the same thing with GWT Java code on the client, except instead of C code, the native language for the browser is JavaScript. That’s how Google came up with the name JavaScript Native Interface (JSNI).

Declaring a Native Method

To declare a native method in JSNI, use Java’s standard native keyword just like you would with JNI. In JNI, the native C code is in a separate file, compiled separately and dynamically loaded at run time. In JSNI, the native JavaScript code is embedded directly in your Java source in a specially formatted comment:

package com.xyz.client;
public class Alert {
public static native void alert(String msg)
/*-{
$wnd.alert(msg);
}-*/;

}

A JSNI comment block begins with /*-{ and ends with }-*/.

As this example shows, when accessing the browser’s window and document objects from JSNI, you must reference them as $wnd and $doc, respectively. Your compiled script runs in a nested frame, and
$wnd and $doc are automatically initialized to correctly refer to the host page’s window and document instead of the frame.

How it Works
In Web mode, the GWT compiler converts the client half of your Java program into JavaScript. So normally, when the compiler sees a method declaration, code inside the braces has to go through some kind of translation process. If it’s a native method, however, the compiler’s job is easier. All it has to do is copy the JavaScript native code directly into the compiled result.

If you’ve used Microsoft’s Visual C++ or the GNU C++ compiler, the effect is much like inline assembler code, except with a much higher level language than assembler. Since JavaScript is interpreted, any errors in the JavaScript code won’t be evident until run-time.

Calling JSNI from Java
Calling a JSNI method from Java1 is no different than calling a regular Java method. Here’s an example:

button1.addClickListener(new ClickListener() {
public void onClick(Widget sender) {
Alert.alert("clicked!");
}
});

The caller can’t really tell if the method is native or not. This gives you some flexibility in changing your mind later about how the method is implemented.

Calling Java from JSNI

Going the other way is a little trickier. For example, suppose you pass an object to a JSNI method and you need to access a field or call a method in that object. You’ll need to know how the GWT compiler mangles the Java field and method names so you can access them from your own JavaScript code.

Accessing Java fields

Object Oriented purists would say that you shouldn’t access fields of a Java class directly because it makes it harder to change the implementation of that class later. But hey, we’re writing native code here so we can cut a few corners. The syntax for accessing a Java field is:

obj.@class::field


where:
obj is the object instance being referenced. For static variables, leave off the instance expression and the trailing period.
class is the fully-qualified name of the class in which the field is declared (or a subclass thereof).
field is the name of the field being accessed.

Invoking Java methods

Calling methods uses a syntax similar to accessing fields, except you must also supply the signature of the method you’re calling. The reason for that is that Java methods can be overloaded, i.e., two methods can have the same name but take different parameters.

The syntax is:

obj.@class::method(sig)(args)

where:
obj is the object instance being referenced. For static methods,
omit the instance expression and the trailing period.
class is the fully-qualified name of the class in which the method is declared (or a subclass thereof).
method is the name of the method being called.
sig is the internal Java method signature (see Section 7.4, Method signatures ).
args is the actual argument list passed to the method.

Method signatures
JSNI method signatures are exactly the same as JNI method signatures except that the method return type is left off. That’s because it’s not needed to figure out which overloaded method you’re referring
to. The following table shows these type signatures:

For example, the Java method:
long f (int n, String s, int[] arr);

has the following type signature:
(ILjava/lang/String;[I)

We will discuss the specific rules for how values passing in and out of JSNI code must be treated.

Example

This code shows some examples of accessing Java fields and methods from within JSNI. It demonstrates passing numbers, strings, booleans, and Java objects into JavaScript. It also shows how a JavaScript method can make a method call on a Java object that was passed in.

public class J2JS {
/** Pass a Java numeric primitive */
public static void testJ2JSNumeric() {
int x = 42;
jsNumeric(x);
}

/**
* Method jsNumeric.
* @param x int
*/

private static native void jsNumeric(int x) /*-{
$wnd.alert(“x is ” + x);
}-*/
;

/** Pass a Java String */
public static void testJ2JSString() {
String s = "my string";
jsString(s);
}

/**
* Method jsString.
* @param s String
*/

private static native void jsString(String s) /*-{
$wnd.alert("s is " + s);
}-*/
;

/** Pass a boolean */
public static void testJ2JSBoolean() {
boolean b = true;
jsBoolean(b);
}

/**
* Method jsBoolean.
* @param b boolean
*/

private static native void jsBoolean(boolean b) /*-{
$wnd.alert("b is " + b);
}-*/;

/** Pass an arbitrary Java Object */
public static void testJ2JSObject() {
MyJavaObject obj = new MyJavaObject();
jsObject(obj);
}

/**
* Method jsObject.
* @param obj MyJavaObject
*/
private static native void jsObject(MyJavaObject obj) /*-{
$wnd.alert("Calling getText(): " + obj.@MyJavaObject::getTextAt(I)(3));
}-*/;

}

If you look at the source code for GWT you’ll see that much of it is defined in terms of JSNI. Most GWT programmers will never need to define JSNI methods themselves, but it’s nice to know the feature is there if you need it.

Advertisements
 
Leave a comment

Posted by on October 7, 2008 in GWT/ JSNI / COMPILER

 

Tags: , ,

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: