Google Web Toolkit Blog: Getting to really know GWT, Part 1: JSNI

by Prabakaran 2012-07-30 14:33:08






GWT's JavaScript Native Interface (JSNI)

You can easily combine handwritten JavaScript directly into GWT code. It's all JavaScript in the end, of course, so why not allow GWT developers to mix-and-match in any way that's useful? That's what JSNI is all about. It's named similarly to the Java Native Interface (JNI) because it uses the same basic idea: declare a Java method "native" and then use another language to implement it. In the case of JSNI, that other language is JavaScript.
Writing Java methods with JavaScript

JSNI is useful to create a reusable abstraction on top of functionality that is most naturally expressed using JavaScript syntax rather than Java syntax. For example, regular expressions are pleasantly concise in JavaScript, so you can use JSNI to make them directly available in your GWT code. Suppose you wanted a method to flip someone's name around such that their last name comes first, for example turning "Freeland Abbott" into "Abbott, Freeland". (Admittedly, this example is an I18N nightmare.) You can create a short JSNI method to do this:

// Java method declaration...
native String flipName(String name) /*-{

// ...implemented with JavaScript
var re = /(w+)s(w+)/;
return name.replace(re, '$2, $1');

}-*/;

Notice that the method body is really just a glorified Java comment, enclosed by the special tokens /*-{ and }-*/.
Calling Java methods from JSNI

You can go the other direction, too, calling a Java method from JavaScript. Suppose we modified the example above to invoke a callback instead:

package org.example.foo;
public class Flipper {

public native void flipName(String name) /*-{
var re = /(w+)s(w+)/;
var s = name.replace(re, '$2, $1');
this.@org.example.foo.Flipper::onFlip(Ljava/lang/String;)(s);
}-*/;

private void onFlip(String flippedName) {
// do something useful with the flipped name
}
}

Using JSNI to access external JavaScript code

Naturally, you can access any sort of external JavaScript code from within a GWT module. For example, if your HTML page looks like this:





<-- Include the GWT module called "Spiffy" -->


...

Within your Java source, you can access the sayHello() JS function through JSNI:

// A Java method using JSNI
native void sayHelloInJava(String name) /*-{
$wnd.sayHello(name); // $wnd is a JSNI synonym for 'window'
}-*/;

The GWT compiler inlines the extra method call away, so calling the sayHelloInJava() method in your Java source is no more expensive than calling sayHello() directly from handwritten JavaScript.
Creating JavaScript libraries with GWT

You can even create JavaScript-callable libraries from your GWT code. This is a pretty neat trick:

package org.example.yourcode.format.client;
public class DateFormatterLib implements EntryPoint {

// Expose the following method into JavaScript.
private static String formatAsCurrency(double x) {
return NumberFormat.getCurrencyFormat().format(x);
}

// Set up the JS-callable signature as a global JS function.
private native void publish() /*-{
$wnd.formatAsCurrency =
@org.example.yourcode.format.client.DateFormatterLib::formatAsCurrency(D);
}-*/;

// Auto-publish the method into JS when the GWT module loads.
public void onModuleLoad() {
publish();
}
}

You can then access this GWT-created functionality from within any HTML page or another JavaScript library:




<-- Include the GWT module that publishes the JS API -->


<-- Write some JS that uses that GWT code -->


...

Ray Cromwell (of GWT Extreme! fame, among other things) has taken the above JavaScript publishing technique to the extreme with his GWT Exporter project. It creates all the publishing code automagically using GWT's compile-time code generation facility. (Does "compile-time code generation" sound cool? If so, stay tuned for the upcoming posts in this series.)


1637
like
0
dislike
0
mail
flag

You must LOGIN to add comments