MigrateFromGWT

From APIDesign

(Difference between revisions)
Jump to: navigation, search
(GWT Project)
Current revision (05:37, 1 October 2021) (edit) (undo)
(Real HotSpot VM)
 
(13 intermediate revisions not shown.)
Line 1: Line 1:
-
[[GWT]] has a lot of drawbacks which [[Bck2Brwsr]] project addresses by being a real [[JVM]]. As such there is a value in [[MigrateFromGWT|migrating]] to this new system. Moreover the [[MigrateFromGWT|migration]] is quite easy. Let me give you a demo.
+
[[GWT]] has a lot of [[GWT|drawbacks]] which [[Bck2Brwsr]] project addresses by allowing us to use real [[JVM]]. As such there is a value in [[MigrateFromGWT|migrating]] to this new system. Moreover the [[MigrateFromGWT|migration]] is quite easy. Let me give you a demo.
=== [[GWT]] Project ===
=== [[GWT]] Project ===
Line 47: Line 47:
</source>
</source>
-
Of course, this is not typical [[GWT]] application. It does not use [[GWT]] widgets library. True, but the point is different: we want to see if we can convert the low
+
Of course, this is not typical [[GWT]] application. It does not use [[GWT]] widgets library. However the point to demonstrate is different: we want to see if we can convert the low level '''JSNI''' comments into something that can run on top of real [[JDK]]. Because if we can, reimplementing the widgets or other libraries is then ''just'' a bit of work.
-
level '''JSNI''' comments into something that can run on top of real [[JDK]]. Because if we can, reimplementing the widgets or other libraries is then ''just'' a bit of work.
+
 
 +
=== Convert to Annotations ===
 +
 
 +
The first step is to convert comments into something that [[JVM]] can consume. Since [[JDK]]5 the proper way of attaching additional information to methods is to use [[annotations]]. Let's us rewrite the code to use ''@''{{HTML4J|net/java/html/js|JavaScriptBody}} as provided by [[Html4Java|HTML/Java interop API]] (see the whole [http://bits.netbeans.org/html+java/1.7.1/net/java/html/js/package-summary.html interop documentation]). The goal is to have source like this:
 +
 
 +
 
 +
<source lang="java">
 +
public class ButtonApp implements Runnable {
 +
 +
public static void onLoad() {
 +
alert("Initializing...");
 +
html("<button id='x'>Click me!</button>");
 +
onClick("x", new Runnable() {
 +
public void run() {
 +
alert("Button was clicked!");
 +
later(new ButtonApp(), 1000);
 +
}
 +
});
 +
}
 +
 +
public void run() {
 +
alert("One second after that!");
 +
}
 +
 +
@net.java.html.js.JavaScriptBody(args = {"r", "time"}, javacall = true, body =
 +
" window.setTimeout(function() {\n" +
 +
" r.@java.lang.Runnable::run()();\n" +
 +
" }, time);\n" +
 +
" ")
 +
public static native void later(Runnable r, int time);
 +
 +
@net.java.html.js.JavaScriptBody(args = {"html"}, body =
 +
" var b = document.getElementsByTagName(\"body\")[0];\n" +
 +
" b.innerHTML = html;\n" +
 +
" ")
 +
public static native void html(String html);
 +
 
 +
@net.java.html.js.JavaScriptBody(args = {"msg"}, body =
 +
" alert(msg);\n" +
 +
" ")
 +
public static native void alert(String msg);
 +
 
 +
@net.java.html.js.JavaScriptBody(args = {"id", "r"}, javacall = true, body =
 +
" document.getElementById(id).onclick = function() {\n" +
 +
" r.@java.lang.Runnable::run()();\n" +
 +
" };\n" +
 +
" ")
 +
public static native void onClick(String id, Runnable r);
 +
 
 +
}
 +
</source>
 +
 
 +
To help us with migration there is a [[NetBeans]] module that can do this for us automatically (either one by one or as a batch conversion).
 +
 
 +
The syntax of [[Java]] callbacks from [[JavaScript]] is the same as the one defined
 +
by [[GWT]] (e.g. starts with '''@'''). However, thanks to [[AnnotationProcessor]]s, it is now part of [[Javac]] execution - if there is a typo in the class name (''java.lang.Runnable''), method
 +
name (''run''), or its parameters (empty list in this case) an error is emitted during compilation - preventing errors as soon as possible.
 +
 
 +
=== Real [[HotSpot]] [[VM]] ===
 +
 
 +
When we have our libraries converted, we can use them in a [[Knockout4Java]] [[Maven]] archetype project and execute them in regular [[JVM]] while rendering the [[HTML]] content via [[JavaFX]] '''WebView'''. This gives us all the benefits of [[HotSpot]] and real [[Java]] (including features of modern [[JDK]]s). We can use regular [[JVM]] [[debugger]] and verify our [[Java]] application behavior the way we are used to.
 +
 
 +
=== [[Bck2Brwsr]] & other transpilers ===
 +
 
 +
Originally we started with a [[GWT]] application. Now we have a real [[Java]] application, which can run on desktop and render its [[HTML]] UI via [[JavaFX]]. [[Good]], however our original application used to run in a browser. Can we do the same?
 +
 
 +
Yes, we can. With the help of [[Bck2Brwsr]] [[VM]], we can take the same application and repackage it so it runs in a pluginless browser. Just choose ''bck2brwsr'' [[Maven]] configuration and rebuild. Btw. [[TeaVM]] also supports the {{HTML4J|net/java/html/js|JavaScriptBody}} annotation and other transpilers are encouraged to join this ecosystem and do the same.
 +
 
 +
Say farewell to [[GWT]]. Enjoy your [[GWT]]-less [[HTML]]/[[Java]] applications! Long live [[Java]] in browsers!

Current revision

GWT has a lot of drawbacks which Bck2Brwsr project addresses by allowing us to use real JVM. As such there is a value in migrating to this new system. Moreover the migration is quite easy. Let me give you a demo.

Contents

GWT Project

The primary focus right now is to show that the GWT Java to JavaScript native interface methods can easily be migrated to real HotSpot virtual machine. Imagine following application that talks directly to JavaScript in the browser:

public class ButtonApp implements Runnable {
 
   public static void onLoad() {
        alert("Initializing...");
        html("<button id='x'>Click me!</button>");
        onClick("x", new Runnable() {
            public void run() {
                alert("Button was clicked!");
                later(new ButtonApp(), 1000);
            }
        });
    }
 
    public void run() {
        alert("One second after that!");
    }
 
  public static native void later(Runnable r, int time) /*-{
        window.setTimeout(function() {
            r.@java.lang.Runnable::run()();
        }, time);
    }-*/;
 
    public static native void html(String html) /*-{
        var b = document.getElementsByTagName("body")[0];
        b.innerHTML = html;
    }-*/;
 
    public static native void alert(String msg) /*-{
       alert(msg);
    }-*/;
 
    public static native void onClick(String id, Runnable r) /*-{
       document.getElementById(id).onclick = function() {
        r.@java.lang.Runnable::run()();
       };
    }-*/;
 
}

Of course, this is not typical GWT application. It does not use GWT widgets library. However the point to demonstrate is different: we want to see if we can convert the low level JSNI comments into something that can run on top of real JDK. Because if we can, reimplementing the widgets or other libraries is then just a bit of work.

Convert to Annotations

The first step is to convert comments into something that JVM can consume. Since JDK5 the proper way of attaching additional information to methods is to use annotations. Let's us rewrite the code to use @JavaScriptBody as provided by HTML/Java interop API (see the whole interop documentation). The goal is to have source like this:


public class ButtonApp implements Runnable {                                                                                                                                                     
 
    public static void onLoad() {                                                                                                                                                            
        alert("Initializing...");                                                                                                                                                                
        html("<button id='x'>Click me!</button>");                                                                                                                                               
        onClick("x", new Runnable() {                                                                                                                                                            
            public void run() {                                                                                                                                                                  
                alert("Button was clicked!");                                                                                                                                                    
                later(new ButtonApp(), 1000);                                                                                                                                                    
            }                                                                                                                                                                                    
        });                                                                                                                                                                                      
    }                                                                                                                                                                                        
 
    public void run() {                                                                                                                                                                          
        alert("One second after that!");                                                                                                                                                         
    }                                                                                                                                                                                            
 
    @net.java.html.js.JavaScriptBody(args = {"r", "time"}, javacall = true, body = 
        "        window.setTimeout(function() {\n" +                                                                                                                                             
        "            r.@java.lang.Runnable::run()();\n" + 
        "        }, time);\n" + 
        "    ")
    public static native void later(Runnable r, int time);
 
    @net.java.html.js.JavaScriptBody(args = {"html"}, body =
        "        var b = document.getElementsByTagName(\"body\")[0];\n" + 
        "        b.innerHTML = html;\n" + 
        "    ")
    public static native void html(String html);
 
    @net.java.html.js.JavaScriptBody(args = {"msg"}, body =
        "       alert(msg);\n" + 
        "    ")
    public static native void alert(String msg);
 
    @net.java.html.js.JavaScriptBody(args = {"id", "r"}, javacall = true, body =        
        "       document.getElementById(id).onclick = function() {\n" + 
        "        r.@java.lang.Runnable::run()();\n" + 
        "       };\n" + 
        "    ")
    public static native void onClick(String id, Runnable r);
 
}

To help us with migration there is a NetBeans module that can do this for us automatically (either one by one or as a batch conversion).

The syntax of Java callbacks from JavaScript is the same as the one defined by GWT (e.g. starts with @). However, thanks to AnnotationProcessors, it is now part of Javac execution - if there is a typo in the class name (java.lang.Runnable), method name (run), or its parameters (empty list in this case) an error is emitted during compilation - preventing errors as soon as possible.

Real HotSpot VM

When we have our libraries converted, we can use them in a Knockout4Java Maven archetype project and execute them in regular JVM while rendering the HTML content via JavaFX WebView. This gives us all the benefits of HotSpot and real Java (including features of modern JDKs). We can use regular JVM debugger and verify our Java application behavior the way we are used to.

Bck2Brwsr & other transpilers

Originally we started with a GWT application. Now we have a real Java application, which can run on desktop and render its HTML UI via JavaFX. Good, however our original application used to run in a browser. Can we do the same?

Yes, we can. With the help of Bck2Brwsr VM, we can take the same application and repackage it so it runs in a pluginless browser. Just choose bck2brwsr Maven configuration and rebuild. Btw. TeaVM also supports the JavaScriptBody annotation and other transpilers are encouraged to join this ecosystem and do the same.

Say farewell to GWT. Enjoy your GWT-less HTML/Java applications! Long live Java in browsers!

Personal tools
buy