The GWT context 💎

GWT is a powerful tool, but sometimes this power might get perceived as complexity.

Long unnecessary explanation here, if you just want to start with GWT jump to the guide itself.

I think this complexity can be divided into two causes; 1. big projects are complex, and when you try to explain how to solve a complex situation, then the explanation itself is complex. 2. GWT has a huge ecosystem, and there are various solutions for each problem. This forces you to make complex decisions.

But, how did we get there?

GWT was borns in 2006, the evolution of the web ecosystem have been amazing since then, even inside GWT itself there have been a lot of changes, alternatives, and third parties that have created amazing solutions to manage big client-side web APPs.

From 2006 to 2012 GWT was called "Google Web Toolkit", and it was an all-in-one solution. In June 2012, Google handed control to the steering committee and rename the project as "GWT". Since then, GWT has been evolving into a more open tool and most of the architectural solutions embedded into GWT itself have been overcome by third-party alternatives. Nowadays, the number of solutions is huge, and at this point, GWT is really just the core, and it is not biased in how you should organize your code. So, GWT is no longer a web toolkit, no longer client-side framework, it is just a transpiler with a giant ecosystem around it.

For example, nowadays if you want to choose a client architectural pattern, you must choose between gwt-activities, gwtp, errai, react4j, vue-gwt, nalu, and more! or if you are looking for a transport layer you should choose between gwt-rpc, request-factory, resty-gwt, gwtp-rest-dispatch, autorest, and more!

All this complexity (only justified for big projects with experienced java teams) and all these alternative architectural solutions (which is actually a good thing) make it a bit confusing to start with GWT.

Said all this, when should I use GWT? I think that you only should use GWT in a company project if you meet these two points.

you have a senior Java team that already know Java and Web development (HTML5, CSS3, ES6). To develop with GWT you must know browsers, you don't need to be a JavaScript expert, but you need to know a lot around the web world (MDN is your friend). you must want to share Java logic, libs, and tools that you are already using in Java (servers or Android) with the client-side or even iOS with J2ObjC). This is the whole point with GWT, sharing code between platforms. This is useful and it solves a logic-duplication, e.g. whenever you edit a field, you frequently validate it with some rules, but then this is sent to the server and should be validated again. This simple but common use case is beautifully solved with GWT. You write your validator code, and you use it exactly the same validation code on all platforms, giving you the responsiveness in the client-side and also the security of the server-side (cross-platform example).

If you already have various years of experience with GWT you can use it for a lot of things, even small APPs. But to justify the entry effort, you should satisfy those two points. But, eh! before a company project, you can just learn it for fun, and I hope you are here for that!

The starting guide ☝️

To make this guide easier, I'm going to focus on the client-side. Also, I'll make some personal decisions which I think are common and future-proof. But remember, GWT is much more than I'll explain here!. This is what I have chosen:

create a micro client-only APP, so no transport and no view components. Frequently guides start with a client-server app, it is much more complex and when you start with GWT you tend to confuse/mix the client and server sides as just one unique magic virtual machine. Although everything is java, and you can run the same java code in the client or in the server, both are independent runtime environments and this concept should be clear. Also, if you create a client only APP the guide gets much smaller, and you can play with it easier. Even more, I strongly encourage you to find micro-games or micro-apps written in JS or TypeScript and migrate it to GWT. This is a pretty good exercise to get used to GWT (this is, for example, a snake game I migrated from a JS project rxsnake-gwt). it is managed with Maven, no IDE or plugin required, just java+maven . I'll use IntelliJ IDEA. We are not going to use any plugin, IntelliJ Ultimate has GWT support, Eclipse has a super nice plugin, but I personally prefer not to depend on any of that. Also, the problem with those plugins is that the project configuration (classpath mostly) is not easy to keep it exactly the same in the terminal or CI Vs the IDE plugin. So with this solution, Maven solution, you will be able to run, test, and package your GWT in the same way in all those environments. IMO Maven is currently the easiest strategy to compile GWT.

1. Maven basic archetype 💩

First, we create a minimal maven project. You might follow this guide or execute this command if you have maven already installed.



› mvn archetype:generate \ -DarchetypeRepository=https://repo.maven.apache.org/maven2 \ -DarchetypeGroupId=org.apache.maven.archetypes \ -DarchetypeArtifactId=maven-archetype-quickstart \ -DarchetypeVersion=1.4 -DinteractiveMode=false \ -DgroupId=me -DartifactId=hello-app -Dversion=HEAD-SNAPSHOT

I hope you know something about maven . But, if not, note that you can compile, test, and package your app using mvn verify . Run it now! 😉

You can now open the created project in IntelliJ, just click open and go to the folder. IntelliJ detect maven automatically, and it will use the maven configurations to configure your project. I have reformated and removed comments, change the target/source java version to 11 (fun 🥳, we can use var ), and update maven-compiler-plugin to 3.8.1 and maven-surefire-plugin to 2.22.1 . Whenever you change something in the POM IntelliJ will ask you to "import changes", click it to update the project configuration. This is how it should look like:



Try again the mvn verify but this time use the IntelliJ maven menu. Any JDK ≥11 should work, but if you have any problem, just use JDK 11.



I start from this basic maven archetype because I want to remark that the GWT project uses the whole Java ecosystem, and it uses similar patterns but applied to front-end development.

Step 1 diff.

2. GWTify it 🌈

First, modify the pom.xml to add the GWT dependencies and the GWT Maven plugin that will add some useful goals to compile and run GWT. Add this to the dependencies section:



<dependency> <groupId>com.google.gwt</groupId> <artifactId>gwt-user</artifactId> <version>2.9.0</version> </dependency> <dependency> <groupId>com.google.gwt</groupId> <artifactId>gwt-dev</artifactId> <version>2.9.0</version> </dependency>

Those are the minimal GWT dependencies. The gwt-user contains client side java utilities, for example the EntryPoint interface that is used in GWT as an static void main(args) equivalent (more on that later). And gwt-dev contains the compiler and other development tools requeriments.

Then, you need to configure the GWT plugin and define the project as a gwt-app . Add this to the build section:



<plugins> <plugin> <groupId>net.ltgt.gwt.maven</groupId> <artifactId>gwt-maven-plugin</artifactId> <version>1.0.0</version> <extensions>true</extensions> <configuration> <moduleName>me.App</moduleName> <skipModule>true</skipModule> </configuration> </plugin> </plugins>

And this at the beginning, after the artifactId and the version elements:



<packaging>gwt-app</packaging>

This will extend maven adding the GWT specific executions to the maven lifecycle. So for example, after adding this if you run again the mvn package you will notice that there are various new steps, the most important one is the one that runs the GWT compiler including our project source code and outputs the final JS. Note that this doesn't work right now, because we haven't updated the java source code! There are 2 configs, the moduleName points to the main gwt.xml file (explained later) and skipModule is used to avoid a nice but a bit "magically" utility from this plugin that will generate the gwt.xml file for you, for now, I prefer to create it manually in the next step, so I just set the plugin to not generate this file for me.

Update the IntelliJ project so the dependencies get downloaded and added to the project classpath.

Now, we will update the current App class that runs in the JVM to make it run on the client-side. Make App implements com.google.gwt.core.client.EntryPoint , remove the static main method and implement the onModuleLoad with the equivalent code. Simple, right? It is almost the same, main for the JVM and onModuleLoad for GWT. Your class content should be:



package me.client ; import com.google.gwt.core.client.EntryPoint ; import com.google.gwt.dom.client.Document ; import com.google.gwt.dom.client.Text ; import com.google.gwt.user.client.ui.RootPanel ; public class App implements EntryPoint { @Override public void onModuleLoad () { Text textNode = Document . get (). createTextNode ( "Hello World!" ); RootPanel . getBodyElement (). appendChild ( textNode ); } }

I think the code is self-explanatory, but… yep, getBodyElement returns the body of the web page so we can add the Hello World! and see it in our page.

Just one more thing about the App class, move it inside client package (probably your IDE has already complained about that if you have copy&pasted the previous code). This makes it a bit easier. Note that GWT apps are all about sharing code, so you probably end up with a server , shared , and client packages in your project. And although this is a minimal client only example, we will follow this convention, so move it to the client package (warn: if you are using IntelliJ it can change the pom.xml <moduleName> from me.App to me.client.App after moving the App.java to the client package, but it should be me.App so check it out, sometimes IntelliJ is too smart).

Next, create the gwt.xml file called App.gwt.xml (create it in the me package, NOT in the client ). This name should match the package and name that we have configured in the gwt-maven-plugin moduleName configuration. Create the file with this content:



<module> <inherits name= "com.google.gwt.user.User" /> <entry-point class= "me.client.App" /> <!--<source path="client"/>--> <!--<public path="public"/>--> </module>

This file is called a GWT module file. It is required so the GWT compiler knows which sources should be compiled, i.e. GWT does NOT compile everything that is in the classpath, it only compiles the sources indicated in the source tag. It is commented because the module adds those 2 lines implicitly. The source path="client" indicates that all java classes inside the package {module-package}.client will be included, and this is why we have moved App inside the client package. The inherits module is a dependency, this module depends on the gwt.user.User module and User source will depend on other modules recursively. The second line entry-point specify an entry point. So when the GWT final compilation is loaded on the web page, those entry points will be called. This is the onModuleLoad that we have created in the App class. This is the equivalent to the Main-Class manifest property for a jar file.

Finally, create an index.html file in me.public package with this content:



<!DOCTYPE html> <meta http-equiv= "Content-Type" content= "text/html; charset=UTF-8" > <title> GWT • Hello App </title> <script type= "text/javascript" src= "me.App.nocache.js" ></script>

The first 2 lines is a "strong" recomendation. Title just optional, and the unique actual interesting line is the script . This will bootstrap the GWT transpiled code, and after some steps, it will end up calling your onModuleLoad entry point! yeah! As you can see, the name of the file is {moduleName}.nocache.js . The nocache is just an easy convention in GWT, the compiler generates various files, and some of them contain .nocache. and others contains .cache. . Files with .nocache. should NEVER be cached and .cache. can be cached FOREVER. This makes trivial to add filters to the server to add cache headers, this is called GWT perfect caching™.

Note, this public/index.html is a utility that is configured in the GWT module file, but similar to the <source path="client"/> convention, all modules contain an implicit <public path="public"/> line. And, GWT compiler will copy everything from all modules public paths to the final compiler output. BUT, my recommendation is that you try to add as less as possible to public folders. GWT has a lot of option to add managed-resources in your project, the public folder is just a drop-in that GWT copy blindly. I don't want to lose you here with explanations, but, believe me, if you add too many things into a public folder, it might be considered a code-smell. At that point, ask for help (at the end of this post I'll explain where is the best place to ask for help).

Step 2 diff.

3. Package, Run and Debug 🔥

GWT transpiles code to JS and to see the result you will need to open it in your browser. But first, you need to compile and package the project. Run:



mvn package

This will generate the required files and put it in the project target folder. Then, after success, open the result, in mac, you can use open target/hello-app-HEAD-SNAPSHOT/me.App/index.html in the terminal. Otherwise, open that file in your browser or drag the file into the browser window. You should see Hello World! in your browser.

What is happening here? The index.html in me.App folder is the one that we have written previously in the public package. So this is not actually generated by GWT, it is blindly copied from our public resources. This file points to me.App.nocache.js that are placed in the same folder by the GWT compiler. This file is the GWT bootstrapper. It is responsible for choosing the final client permutation. It is called permutation because GWT define a special type of compile property that can be used to choose between different "implementations", and it can use it to generate a specific final compilation results for all possible combination of all those properties, each of this combinations is called a permutation (ex. chrome+es is a permutation for the browser chrome and language Spanish).

If you are able to see the Hello World! that means that all those steps have happened successfully. I suggest to open the dev tools console in your browser and check the network panel, you can see that the browser load the nocache file, and then it loads a weird {hash}.cache.js file which is the actual permutation. You can try out another browser to see that this permutation file is different because by default GWT will generate a specific permutation per-browser. This is configurable, but I'll omit it in this guide. Between version, the unique file that should be checked is the nocache , because if something change, it will point to newly hashed files (this is why cache files can be cached forever).

This is nice, but this is not so nice if you need to debug or re-load with small changes. During development, you will use a special GWT feature called codeserver . The codeserver is a server that will compile and serve the code on the fly. You can run the codeserver using mvn gwt:codeserver , but we are going to use in this case the goal mvn gwt:devmode . Ok, sorry, this is a bit confusing, but this will run 2 servers, the codeserver and another jetty just to open the index.html . I don't want to explain this, because it is a bit confusing and requires a long explanation. But for now, just keep in mind that what we really want and what we are using is the codeserver , and we use devmode only to be able to open the index.html (all this will make more sense in a future tutorial about the server-side). So, please run mvn gwt:devmode . In IntelliJ, you can simply double-click in the gwt:devmode goal in the maven panel, super handy!

If you inspect the log carefully you can see both servers, the codeserver at port 9876 and the second jetty server at 8888. Start with the codeserver . Open it in your browser. For now only check that in the second point, where there is a list of modules, you see your me.App module. Hope you see it! Then, open the other server at port 8888 (both can be opened like localhost:9876 or localhost:8888 in any browser). When you open the jetty server, you will see your module directory, click on me.App/ to open that folder. This will end up opening our index.html , then it will fetch the me.App.nocache.js file but this time (and this is a bit of devmode magic) it will use a special nocache.js file that will detect the permutation and also it will communicate with the codeserver , compile the code on the fly and sent the permutation plus source codes to your browser. During a few seconds, you should notice a "Compiling me.App" dialog that will disappear on success. You can change the hello world message, e.g. remove the world part, and reload the page. This will fire the compilation again. This is the standard development lifecycle, edit and reload.

Now, I will ask you to move to chrome. You can do this in any browser, but easier to explain with one specific browser. Go to the devtools and open the Sources tab. Now find a resource (shortcut ctr+p or cmd+p) and write App to find our entry point class. You should see the Java file in the browser, this is because the codeserver generate JS source maps automatically, and chrome resolve that mapped Java sources and shows it in the devtools . Click on the RootPanel.getBodyElement line number to add a breakpoint, it should turn blue indicating an active breakpoint. Then, reload the page. If you have done it correctly, the debugger should stop in that line, you should be seeing something like this:

This is all you need to debug GWT code. But, note that you can write a lot of code in pure Java, this code, especially if you avoid the UI final layer, is trivial to run in JVM or to test using JUnit. GWT is all about sharing, and about using Java tooling, so if you are developing tools like for example a spatial-index, it is much easier and faster to test, run and debug it using plain Java. And then use it on the client-side.

4. Spice it up 🌮

And this is where the personal touch gets crazy. Now I'm going to explain how to add 2 libs, a "pure" JS lib (Elemental2), and a "pure" Java lib (RxJava). I have chosen both libraries on purpose as opposite extreme cases. Using the "pure" JS libraries you should see how you can access native JS code in GWT and how easy and lightweight it is. And using the "pure" Java lib you'll see that in GWT you can use classic pure Java libraries in the browser. But, we are not going to depend directly on those 2 libs, instead we will use this dependency graph:

Elemental2 is a Google library that exposes the whole Browser API in Java. The unique minor problem with this library is that in some cases the API is not javaish enough, specifically, events and element creation requires casts which is not common in the Java world. So, although we will use this library behind scenes, we are going to depend directly on a super small RedHat library called Elemento that add those missing parts. This library is a handcrafted API for elements and events, a beautiful library that gives us the power of JS with the type-safety of Java.

RxGWT is a set of utilities to use RxJava in GWT, i.e. same as RxAndroid but for GWT. RxGWT depends on RxJava GWT, a thin GWT adapter library over RxJava. Yep, ok, you cannot depend directly on RxJava, but if you go to the repo you will see that there are just a few minor changes and configurations to make it work in GWT, almost all of the actual RxJava source-code is the same.

Remember my recommendation; the idea with those 2 libraries is that you get able to find JS+RxJS projects and migrate to Java+RxJava with GWT using your Java knowledge! This is an awesome way to gets used to GWT and there are a lot of fun micro reactive projects that can be improved!

To add this dependencies update the pom.xml with:



<?xml version="1.0" encoding="UTF-8"?> <project xmlns= "http://maven.apache.org/POM/4.0.0" xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation= "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" > <modelVersion> 4.0.0 </modelVersion> <groupId> me </groupId> <artifactId> hello-app </artifactId> <version> HEAD-SNAPSHOT </version> <packaging> gwt-app </packaging> <name> hello-app </name> <properties> <project.build.sourceEncoding> UTF-8 </project.build.sourceEncoding> <maven.compiler.source> 11 </maven.compiler.source> <maven.compiler.target> 11 </maven.compiler.target> </properties> <dependencyManagement> <dependencies> <dependency> <groupId> com.google.gwt </groupId> <artifactId> gwt </artifactId> <version> 2.9.0 </version> <type> pom </type> <scope> import </scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId> com.google.gwt </groupId> <artifactId> gwt-user </artifactId> </dependency> <dependency> <groupId> com.google.gwt </groupId> <artifactId> gwt-dev </artifactId> </dependency> <dependency> <groupId> org.jboss.gwt.elemento </groupId> <artifactId> elemento-core </artifactId> <version> 0.9.1-gwt2 </version> </dependency> <dependency> <groupId> com.intendia.gwt.rxgwt2 </groupId> <artifactId> rxgwt </artifactId> <version> 2.2 </version> </dependency> <dependency> <groupId> com.intendia.gwt </groupId> <artifactId> rxjava2-gwt </artifactId> <version> 2.2.10-gwt1 </version> </dependency> <dependency> <groupId> junit </groupId> <artifactId> junit </artifactId> <version> 4.11 </version> <scope> test </scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId> net.ltgt.gwt.maven </groupId> <artifactId> gwt-maven-plugin </artifactId> <version> 1.0.0 </version> <extensions> true </extensions> <configuration> <moduleName> me.App </moduleName> <skipModule> true </skipModule> </configuration> </plugin> </plugins> <pluginManagement> <plugins> <plugin> <artifactId> maven-compiler-plugin </artifactId> <version> 3.8.1 </version> </plugin> </plugins> </pluginManagement> </build> </project>

We have added a special dependency of type pom and scope import called BOM. This is a utility dependency that asserts that all dependencies defined in the BOM will be of the version specified in the BOM itself. This is useful because we can end up with various gwt-xxx libs with various versions and this might be a problem, so this BOM assert that all GWT core dependencies are at the same version.

Alos, we have added 3 new explicit dependencies, elemento-core , rxgwt and rxjava-gwt .

Then, go to your App.gwt.xml module file and add this 2 dependencies:



<inherits name= "com.intendia.rxgwt2.RxElemento" /> <inherits name= "org.jboss.gwt.elemento.Core" />

If you still have the gwt:devmode running you will need to restart. There are new maven dependencies, and as those dependencies should be added to the classpath, you will get forced to restart it. It is just a few seconds, so no problem. Stop it and run mvn gwt:devmode again. Open localhost:8888 and go to app.App and check that you still see the Hello World! in your browser.

Now, update the content of App.java with:



package me.client ; import com.google.gwt.core.client.EntryPoint ; import org.jboss.gwt.elemento.core.Elements ; public class App implements EntryPoint { @Override public void onModuleLoad () { Elements . body (). add ( "Hello World!" ); } }

Cool, this is much less verbose. Elements is an elemento utility, it contains all those user-friendly type-safe element APIs. Most of the types of the Elements methods return builders which are wrappers around the actual elemental2 type. You can extract the elemental2 type calling get() . At that point, you are accessing the browser API almost directly. GWT will transpile the Java source-code to JS but a line of code like this DomGlobal.document.body.background = "red"; will gets translated to document.bod.background = 'red'; , almost the same. TIP: Navigating through the elemental2 source code is a good strategy to learn how to map native API in Java GWT.

Now we are going to apply RxJava, update the content of App.java to:



package me.client ; import com.google.gwt.core.client.EntryPoint ; import com.intendia.rxgwt2.elemento.RxElemento ; import elemental2.dom.HTMLElement ; import org.jboss.gwt.elemento.core.Elements ; import static elemental2 . dom . DomGlobal . document ; import static org . jboss . gwt . elemento . core . EventType . mousemove ; public class App implements EntryPoint { @Override public void onModuleLoad () { HTMLElement el = Elements . span (). style ( "font-weight: bold;" ). get (); Elements . body (). add ( "mouse position: " ). add ( el ); RxElemento . fromEvent ( document , mousemove ) . subscribe ( ev -> el . textContent = ev . clientX + ", " + ev . clientY ); } }

Oh! the hello world message has been removed 😅! We have added a span and an event listener for mousemove events in the page document . This is a pretty simple code, but with lots of nice things! Elements.span() is an elemento builder, see how easy is to set the style and to get the element using its fluent API. HTMLElement is an elemental2 type, which is almost like using the browser API directly. RxElemento.fromEvent is a RxGWT utility that combines the elemento type-safe events with RxJava. This is the actual type Observable<MouseEvent> returned by fromEvent , i.e. it is an Observable of the concrete event type. This observable will add a new event listener to each subscription and will remove it on unsubscribe. The last line is the actual subscription that will update the el span element with the mouse client coordinates.

In this micro example, we are mixing a pure Java lib to subscribe and compose events with a browser-native API. It's so simple that does not surprise, but this is pretty awesome and powerful if you think about it 🤯! Actually, if you are an android developer and you have a lot of experience with UI, MVP, Dagger, RxJava and all those fancy things to manage your UI state? Then this should be your starting point to start applying all this knowledge to create web-based UI applications!

Step 4 diff.

Conclusion 👋

Just joking, no conclusion at all, only some notes of where you should go from here. Hope you like it. GWT is a super powerful transpiler. We have not even talked about how it is able to manage resources (JS, CSS, HTML, translations, images, and more) and embed it all into one single JS file. It is huge, but even ignoring all those extra utilities, just as a "simple" transpiler, it is more than enough to be useful for all those Java experts that want to write browser code.

If you like this intro, I'll try to make some client-server tutorial. I really think that client only APPs is the best starting point, but yep, people love the idea of writing the client and server in the same language and probably almost everyone using GWT is using it with this goal in mind. But, of course, this tutorial will be a pretty biased one too 😬.

There is a project to start with GWT using a spring boot approach. I personally prefer a manual approach as explained in this guide because the spring boot approach adds many dependencies and makes you feel a bit like you have loose control. But if you like it, then you will love this project gwt-boot-samples and it is even easier to start with. Anyway, this project has various modern popular solutions, so even if you don't use the dependencies itself, you can get inspired and configure it manually.

Finally, my recommendation about asking for help:

stackoverflow gwt - pretty obvious, but yep, the best place to standard problems

gitter gwt - gitter chat, this is pretty active, if you have no idea or have a quick question this is the best place

groups gwt here there are a lot of old questions, also there are various specific groups for contributors, steering committee, various classic GWT libs, and more

Those 3 places should be enough. But, if you want to find more things, maybe some surprise, then go to awesome gwt where there are an infinite list of useful GWT resources, tutorial, libs, videos, blogs, and more!