Mix handwritten JavaScript into your Java classes to access low-level browser functionality.
native method and write the body into
a specially formatted comment.Writing JSNI methods is a powerful technique, but should be used sparingly. JSNI code is less portable across browsers, more likely to leak memory, less amenable to Java tools, and hard for the compiler to optimize.
We think of JSNI as the web equivalent of inline assembly code. You can:
native and contain JavaScript
code in a specially formatted comment block between the end of the
parameter list and the trailing semicolon. A JSNI comment block begins
with the exact token /*-{ and ends with the exact
token }-*/. JSNI methods are be called just like any
normal Java method. They can be static or instance methods.
public static native void alert(String msg) /*-{
$wnd.alert(msg);
}-*/;
JavaScript calls into Java methods are of the form
[instance-expr.]@class-name::method-name(param-signature)(arguments)where
[instance-expr.]@class-name::field-name
public class JSNIExample {
String myInstanceField;
static int myStaticField;
void instanceFoo(String s) {
// use s
}
static void staticFoo(String s) {
// use s
}
public native void bar(JSNIExample x, String s) /*-{
// Call instance method instanceFoo() on this
this.@com.google.gwt.examples.JSNIExample::instanceFoo(Ljava/lang/String;)(s);
// Call instance method instanceFoo() on x
x.@com.google.gwt.examples.JSNIExample::instanceFoo(Ljava/lang/String;)(s);
// Call static method staticFoo()
@com.google.gwt.examples.JSNIExample::staticFoo(Ljava/lang/String;)(s);
// Read instance field on this
var val = this.@com.google.gwt.examples.JSNIExample::myInstanceField;
// Write instance field on x
x.@com.google.gwt.examples.JSNIExample::myInstanceField = val + " and stuff";
// Read static field (no qualifier)
@com.google.gwt.examples.JSNIExample::myStaticField = val + " and stuff";
}-*/;
}
| Incoming Java type | How it appears to JavaScript code |
|---|---|
a JavaScript numeric value, as in var x = 42; |
|
String | a JavaScript string, as in var s = "my string"; |
boolean | a JavaScript boolean value, as in var b = true; |
a JavaScriptObject that must have originated from
JavaScript code, typically as the return value of some other JSNI method
|
|
| an opaque value that can only be passed back into Java code | |
Object | an opaque value accessible through special syntax |
| Outgoing Java type | What must be passed |
|---|---|
a JavaScript numeric value, as in return 19; |
|
String | a JavaScript string, as in return "boo"; |
boolean | a JavaScript boolean value, as in return false; |
a native JavaScript object, as in return
document.createElement("div") |
|
Object (including arrays) | a Java Object of the correct type that must have
originated in Java code; Java objects cannot be constructed from "thin
air" in JavaScript |
byte,
short, char, int,
long, float, or double.
You must ensure the value is appropriate for the declared type. Returning
3.7 when the declared type is int will
cause unpredictable behavior. null and JavaScript null are
identical and always legal values for any non-primitive Java type.
JavaScript undefined is not identical to
null; never return undefined from a JSNI
method or unpredictable behavior will occur. com.google.gwt.dev.shell.HostedModeException detailing
the problem. This exception is not
translatable and never
thrown in web mode. An exception that originates in a JSNI method and escapes into Java code can be caught as a JavaScriptException. Relying on this behavior is discouraged because JavaScript exceptions are not usefully typed. The recommended practice is to handle JavaScript exceptions in JavaScript code and Java exceptions in Java code.
When a JSNI method invokes a Java method, a more complex call chain results. An exception thrown from the inner Java method can safely pass through the sandwiched JSNI method back to the original Java call site, retaining type fidelity. It can be caught as expected. For example,
foo() calls JSNI method
bar()
bar() calls Java method
baz()
baz() throws an exceptionbaz() will propagate through
bar() and can be caught in foo().