This is the JavaScript Native Interface (JSNI) used in GWT to use code written in JavaScript.
Allows you to write your own JavaScript and use it in the client side of Java code. For example, the lowest-level functionality of some of the core GWT classes is written in JavaScript.
Writing and using JSNI methods is a powerful technique, but should be used with caution. JSNI code is less cross-browser, a high probability of memory leakage, less amenable to Java-based tools and is not an easy task for compiler to optimize.
JSNI provides such features as:
- executing java methods directly in javascript
- wrapping safe Java methods around existing JavaScript
- calling javascript in java code and vice versa
- read and write java fields from javascript
- using debug mode for both Java and JavaScript (script debugger)
JSNI methods are declared as native and contain JavaScript code in the spec. comments block format that starts with / * - {and ends with * / -}. JSNI methods are called just like any Java method. JSNI syntax is a directive for Java to a JavaScript compiler to accept any text between a declared block of comments as valid JavaScript code and injects it into the GWT files created. During GWT compilation, the compiler performs some JavaScript syntax checking of the code inside the method, then generates interface code to convert the method arguments and return values.
A simple example of a JSNI method that displays a JavaScript dialog:
public static native void alert(String msg) /*-{ $wnd.alert(msg); }-*/;
Note that the code does not refer to the JavaScript window object directly inside the method. When accessing the browser window and document objects from JSNI, you should refer to them as $ wnd and $ doc, respectively. This compiled script works in an embedded frame, $ wnd and $ doc are automatically initialized correctly referring to the window and the document of the host page. Let's look at another example that throws an exception:
public static native int exampleThrewException() /*-{ return "not a number"; }-*/; try { int value = exampleThrewException(); GWT.log("We got a value " + value, null); } catch(Exception ex) { GWT.log("JSNI method exampleThrewException() threw an exception", ex); }
This example is compiled as Java, and its syntax is checked by the GWT compiler as valid JavaScript. But if you run the example in development mode, it will throw out a trace. an exception.
com.google.gwt.dev.shell.HostedModeException: Something other than an int was returned from JSNI method '@com.dmitrynikol.webstorage.gwt.client.WebStorageGwtApp::exampleThrewException()': JS value of type string, expected int at com.google.gwt.dev.shell.JsValueGlue.getIntRange(JsValueGlue.java:266) at com.google.gwt.dev.shell.JsValueGlue.get(JsValueGlue.java:144) at com.google.gwt.dev.shell.ModuleSpace.invokeNativeInt(ModuleSpace.java:247) at com.google.gwt.dev.shell.JavaScriptHost.invokeNativeInt(JavaScriptHost.java:75) …....
In this case, neither the Java IDE nor the GWT compiler will tell you that there is a mismatch between the type of code inside the JSNI method and the Java declaration. The generated interface code on GWT caught the problem in runtime in development mode. When you run the code in run mode, you cannot see the exception, since Dynamic JavaScript typing hides problems of this kind.
How to access Java methods and fields from JavaScript?
It can be very useful to manipulate Java objects within the JavaScript implementation of the JSNI method. But, since JavaScript uses dynamic typing, and Java uses static typing, you must use a special syntax.
Calling Java methods from JavaScript
Calling Java methods from JavaScript is similar to calling Java methods from C to JNI. JSNI borrows the JNI method signature approach to distinguish between overloaded methods. JavaScript calls in Java methods have a trace. view:
[instance-expression]@class-name::method-name(param-signature)(arguments)
- instance-expression - must be present when calling the instance method and must be absent when calling the static method
- class-name - the full name of the class in which the method is declared
- param-signature is the internal signature of the Java method defined in JNI Type Signatures, but without the back signature of the return type of the method, since it is not necessary when choosing a reboot
- arguments - a list of arguments to pass to the method being called.
Calling Java constructor from javascript
Let us compare the example of Java expression against JSNI expressions:
class Main { public Main() {/** */} public Main(int i) {/** */} static class StaticInner { public StaticInner() {/** */} } class TestInner { public TestInner(int i) {/** */} } }
- new Main () equals @ com.webstorage.gwt.client.Main :: new () ()
- newStaticInner () equals @ com.webstorage.gwt.client.Main.StaticInner :: new () ()
- mainInstance.new TestInner (135) equals @ com.webstorage.gwt.client.Main.TestInner :: new (Lcom / dmitrynikol / webstorage / gwt / client / Main; I) (mainInstance, 135)
Access to Java fields from JavaScript
Consider an example of access to static fields and fields of an instance of a class from JSNI:
class JSNI { String instanceField = "test"; static double staticField = 12345; public void instanceMethod(String value) { /** just use 'value' */ Window.alert("execute instanceMethod"); } public static void staticMethod(String value) { /** just use 'value' */ Window.alert("execute staticMethod"); } /** * different situation of accessing Java fields from JavaScript by JSNI */ public native void execute(JSNI jsni, String value) /*-{ // call instance method runInstanceMethod() on this this.@com.dmitrynikol.webstorage.gwt.client.JSNI::instanceMethod(Ljava/lang/String;)(value); // call instance method runInstanceMethod() on jsni jsni.@com.dmitrynikol.webstorage.gwt.client.JSNI::instanceMethod(Ljava/lang/String;)(value); // call static method staticMethod() @com.dmitrynikol.webstorage.gwt.client.JSNI::staticMethod(Ljava/lang/String;)(value); // read instance field on this var valueFromInstanceField = this.@com.dmitrynikol.webstorage.gwt.client.JSNI::instanceField; $wnd.alert(valueFromInstanceField); // write instance field on jsni jsni.@com.dmitrynikol.webstorage.gwt.client.JSNI::instanceField = value + " value"; $wnd.alert(jsni.@com.dmitrynikol.webstorage.gwt.client.JSNI::instanceField); // access to static field (without qualifier as you can see) $wnd.alert(@com.dmitrynikol.webstorage.gwt.client.JSNI::staticField + 1); }-*/; }
Calling a Java Method from JavaScript
Sometimes it is necessary to access a method or constructor defined in GWT in external JavaScript code. This code can be written by hand and included in another js file or it can be part of a third-party library. In this case, the GWT compiler will not be able to create an interface between the user's JavaScript code and the generated JavaScript via GWT directly. This relationship can be accomplished by assigning a method via JSNI as an external, globally visible JavaScript name that can refer to hand-written JavaScript.
..... public static int recalculate(int period, float rate, int overtime) { /** ... */ } public static native void exportStaticMethod() /*-{ $wnd.count = $entry(@com.dmitrynikol.webstorage.gwt.client.JSNI::recalculate(IFI)); }-*/; .....
It should be noted that the reference to the exported method was wrapped in a call to the $ entry method. This function ensures that the Java derived method runs with an uncaught installed exception handler.
When initializing an application, you just need to call ClassName.exportStaticMethod () from the starting GWT point. This will assign the function to a variable in the object window called. count.
Parameters and return types of JSNI methods are declared as Java types. Let's look at the picture specific rules of how the values passing to and from the JSNI code should be processed.

Exceptions and JSNI
Exceptions can be thrown during the execution of any normal Java code or JavaScript code in the JSNI method. When an exception is generated in the JSNI method, it is propagated up the call stack and caught in the Java catch block. A javascript-thrown exception is wrapped in a JavaScriptException object at the time it was caught. This wrapper object contains only the class name and a description of the JavaScript exception that occurred. It is recommended to handle JS exceptions in JS code, and Java exceptions in Java code. Java exceptions can safely maintain the identity propagated through JSNI methods.
For example:
- Java method firstExecute () calls JSNI method nativeMethod ()
- nativeMethod () inside calls the secondExecute () Java method
- and secondExecute () throws an exception.
The exception from secondExecute () will be distributed via the nativeMethod () and can be caught in the firstExecute () method. The exception will retain its type and identification.
(The material is taken here: We understand the GWT JavaScript Native Interface (JSNI) )