Project Structure & Modules

This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production.

The reference material consulted while preparing these pages is listed in the section bibliography.

This page is written against GWT 2.13.1 (2026-06-19), net.ltgt.gwt.maven:gwt-maven-plugin 1.3.0 (2026-05-31), JDK 21 to run the build tools, Java source level 17 for the code (the modular-webapp archetype default), and the Jakarta Servlet 6.0 API on the server side, checked on 2026-10-08. It is about how a GWT project is laid out and wired together, so it mixes four kinds of files: client code (compiled to JavaScript), shared code (compiled twice, to JavaScript and to JVM bytecode), server code (plain Java on a servlet container), and build/configuration files (the module XML, the host page and the POMs). Every module-XML and Maven example was compiled in a scratch copy of the three-module Bookshelf application, and the error messages quoted in the pitfalls are the ones those runs printed. The running scenario of the section, the Bookshelf (a catalogue of books that later gains authors, reviews and loans), is used throughout.

What a module is

A GWT module is a unit of configuration. It is an XML file named Something.gwt.xml that lives in a Java package on the classpath, and it tells the GWT compiler five things: which other modules it builds on, which packages contain Java source that may be translated to JavaScript, which directories contain static files that must be published next to the generated JavaScript, which classes are entry points, and which deferred-binding rules, properties and linkers apply. Nothing outside the source path of a module is visible to the compiler, which is what lets client, shared and server classes live in the same project without the compiler ever trying to translate a servlet.

A module has two names. Its logical name is the package plus the file name without extension, such as com.example.bookshelf.App for com/example/bookshelf/App.gwt.xml; it is what <inherits> and the compiler command line use. Its output name is the logical name unless rename-to is given, in which case it becomes the short name of the output directory and of the nocache.js file (bookshelf/bookshelf.nocache.js).

The Bookshelf module graph looks like this. The App module is the one that is compiled; Shared is a library that both the browser and the server use; everything else comes from gwt-user.

flowchart TD app["com.example.bookshelf.App
rename-to = bookshelf
entry point: client.App"] shared["com.example.bookshelf.Shared
gwt-lib, source path: shared"] user["com.google.gwt.user.User"] clean["...user.theme.clean.Clean"] i18n["com.google.gwt.i18n.I18N"] json["com.google.gwt.json.JSON"] place["...place.Place"] activity["...activity.Activity"] editor["...editor.Editor"] core["com.google.gwt.core.Core
implicit in every module"] app --> shared app --> user app --> clean app --> i18n app --> json app --> place app --> activity app --> editor shared --> user user --> core clean --> user

Client, shared and server: package conventions

The Developer Guide recommends one root package per project, with the module XML in it and three conventional sub-packages below it. Only the first two are ever seen by the GWT compiler.

Package Holds Seen by the GWT compiler

client

Code that runs in the browser: entry point, widgets, presenters, UiBinder templates, the asynchronous RPC interfaces. May use only the JRE emulation and GWT client classes.

Yes, by default (<source path="client"/> is implied when no <source> is declared)

shared

Code used by both sides: DTOs, validators, the synchronous service interfaces, constants. Must stay inside the emulated JRE.

Only when declared with <source path="shared"/> (the archetype does so)

server

Servlets, repositories, security filters. Anything that needs the full JDK.

Never

public (directory, not a package of classes)

Static files published next to the compiled script: CSS, images, small scripts.

Yes, as the default public path

The Bookshelf follows the layout that the modular-webapp archetype generates, one Maven module per concern, which has the nice side effect that a stray java.io.File in the client module is a compile error rather than a code review comment:

bookshelf/                                 parent POM (pom packaging, BOM import, plugin versions)
  bookshelf-shared/                        gwt-lib: shared code, built once, used by client and server
    src/main/module.gwt.xml                module template for com.example.bookshelf.Shared
    src/main/java/com/example/bookshelf/shared/   Book, BookPage, CatalogService, CatalogServiceAsync
    src/main/super/...                     optional super-sources (see below)
  bookshelf-client/                        gwt-app: the module that is compiled to JavaScript
    src/main/module.gwt.xml                module template for com.example.bookshelf.App
    src/main/java/com/example/bookshelf/client/   App (EntryPoint), views, activities, places
    src/main/resources/com/example/bookshelf/public/   static files (optional)
  bookshelf-server/                        war: servlets, WEB-INF/web.xml, host page
    src/main/java/com/example/bookshelf/server/    CatalogServiceImpl and friends
    src/main/webapp/index.html             the host page
    src/main/webapp/WEB-INF/web.xml

The same split, drawn as the three kinds of code and where each one is executed:

flowchart LR subgraph jvmserver["Servlet container (JVM)"] server["server package
servlets, repositories"] end subgraph both["Compiled twice"] shared["shared package
DTOs, service interfaces"] end subgraph browser["Browser (JavaScript)"] client["client package
entry point, widgets"] end client --> shared server --> shared client -. "GWT-RPC, JSON" .-> server

The Developer Guide describes the older Ant layout (src, war, test, war/WEB-INF/lib/gwt-servlet.jar) that the removed webAppCreator produced. The Maven layout above puts the same things under src/main/..., and the archetype’s server module is the war directory of the guide. The shape of the rules is the same: one root package, a client package that is translated, a server package that is not, and static files on a public path.

The module XML file

A module file is small when the project follows the conventions. This is the module template of bookshelf-client in the scratch Bookshelf, including the internationalisation and CSS settings that the later pages of the section (Internationalization and Styling: CSS & GSS) explain:

<?xml version="1.0" encoding="UTF-8"?>
<module>
  <inherits name="com.google.gwt.user.User" />
  <inherits name="com.google.gwt.user.theme.clean.Clean" />
  <inherits name="com.google.gwt.i18n.I18N" />
  <inherits name="com.google.gwt.place.Place" />
  <inherits name="com.google.gwt.activity.Activity" />
  <inherits name="com.google.gwt.editor.Editor" />

  <source path="client" />
  <source path="shared" />

  <entry-point class="com.example.bookshelf.client.App" />

  <extend-property name="locale" values="en" />
  <extend-property name="locale" values="es" />
  <set-configuration-property name="CssResource.enableGss" value="true" />
  <set-configuration-property name="CssResource.conversionMode" value="strict" />
</module>

The Developer Guide’s reference lists only the "most commonly used" elements. The table below covers the elements named by the guide plus the ones the module parser (ModuleDefSchema, GWT 2.13.1) actually accepts and that matter for project structure. Elements for deferred binding (replace-with, generate-with, define-property, property-provider, the when-* conditions) are only listed here and belong to Deferred Binding & Generators.

Element Purpose Defaults and notes

<module rename-to="short">

Root element. rename-to replaces the long logical name as the output name.

The guide names two uses: a short output directory (typical) and a "working module" that restricts permutations. The schema also accepts a type attribute, which the guide does not document, so avoid it.

<inherits name="logical.Module"/>

Brings in everything another module declares (source, public path, entry points, properties, rules), as if its XML had been pasted in.

Every module implicitly inherits com.google.gwt.core.Core first, so properties can be overridden afterwards.

<entry-point class="..."/>

Names a class that implements EntryPoint and has a no-argument constructor.

Several are allowed, also from inherited modules; they run in order of appearance, each after the previous onModuleLoad returns.

<source path="client"/>

Adds a sub-package (and its descendants) of the module’s package to the source path.

If no <source> and no <super-source> is declared, client is implied. Declaring any one turns the implicit one off.

<public path="public"/>

Adds a sub-package to the public path: files there are copied to the module’s output directory.

If no <public> is declared, public is implied.

<super-source path="super"/>

Re-roots a source path: the path prefix is stripped, so super/java/util/UUID.java is seen as java/util/UUID.java.

Declaring one also turns off the implied client source path. Replaces a class of the same name found on a normal source path.

<stylesheet src="..."/>

Links a CSS file into the host page when the module loads.

Relative URLs are resolved against the module base URL (so usually a file on the public path); absolute URLs are used verbatim. Works with the default linker.

<script src="..."/>

Injects an external JavaScript file before onModuleLoad.

Not supported by the default xsiframe linker: the compile fails unless xsiframe.failIfScriptTag is FALSE, in which case the tag is ignored (see below).

<servlet path="/x" class="..."/>

Mounts a servlet for GWT’s embedded development server.

The path must start with / or the module fails to load. Obsolete in practice: since GWT 1.6 servlets come from web.xml, and since 2.13 the development server serves only static files.

<set-property name="p" value="v"/>

Fixes a deferred-binding property to a value, removing the other values (and so permutations).

Example in the "working module" below.

<extend-property name="p" values="a,b"/>

Adds allowed values to a property; accumulates through inheritance.

The standard use is declaring locales.

<set-configuration-property name="p" value="v"/>

Sets a compile-time configuration property, such as CssResource.enableGss.

A property that has no matching define is accepted for backwards compatibility but logs a warning.

<add-linker name="x"/>

Selects a linker by its registered name.

Additive for pre- and post-linkers; only the last primary linker is used. xsiframe is the default.

<collapse-property name="p" values="*"/>

Merges permutations that differ only in the listed values of one deferred-binding property.

The values must be ones previously defined for the property; * is a glob.

<collapse-all-properties/>

Collapses every deferred-binding property, producing one permutation.

Takes an optional value attribute that defaults to true.

<resource path="..."/>

Registers a resource path with the module.

Accepted by the parser but not described in the guide, so avoid it.

<define-linker>, <define-configuration-property>, <extend-configuration-property>, <clear-configuration-property>, <define-property>, <set-property-fallback>, <property-provider>, <replace-with>, <generate-with>, <fail>, <all>, <any>, <none>, <when-type-is>, <when-type-assignable>, <when-property-is>, <when-linker-added>

Properties, linkers and deferred binding.

Covered on the deferred-binding page of the section.

Naming, rename-to and "working modules"

The guide’s own example of rename-to shows the first use, a short module name:

<module rename-to="bookshelf">
  <inherits name="com.google.gwt.user.User" />
  <entry-point class="com.example.bookshelf.client.App" />
</module>

The short name matters beyond tidiness. GWT.getModuleBaseURL() is the URL of the output directory, and @RemoteServiceRelativePath("catalog") is resolved against it, so the Bookshelf’s catalog service lives at /bookshelf/catalog precisely because the module is renamed to bookshelf. Static files from the public path are reached with GWT.getModuleBaseForStaticFiles() followed by the file name.

The second use is a working module: a module that inherits the real one and pins properties, to cut the number of permutations during development. The guide’s example pins user.agent to ie6, a value that no longer exists. In GWT 2.13.1 UserAgent.gwt.xml defines gecko1_8 and extends it with safari only. The same trick with current values, written for the Bookshelf’s small slots module, compiled to exactly one permutation:

<module>
  <inherits name="com.google.gwt.user.User" />
  <entry-point class="com.example.bookshelf.slots.client.Slots" />
  <set-property name="user.agent" value="gecko1_8" />
  <set-property name="locale" value="default" />
</module>

On the full bookshelf-client module, which has three locale values (default, en, es) and two user agents, the compiler printed Compiling 6 permutations; the slots module above printed Compiling 1 permutation. A working module is a development tool: ship the real module.

Inheritance and the standard modules

<inherits> is the only way to make library code visible. The Developer Guide asks you to inherit "at least the User module", and its table of standard modules is from GWT 1.5, which is why it lists only five modules and three themes. The modules that exist in the 2.13.1 gwt-user and that a Bookshelf-style project meets most often are:

Logical name What it gives you Notes

com.google.gwt.core.Core

The GWT class, EntryPoint, the JRE emulation, the definitions of the linkers and compiler parameters

Inherited implicitly by every module.

com.google.gwt.user.User

Widgets, panels, events, HTTP, RPC support, timers, Window, media, storage, geolocation, text, UiBinder, resources and SafeHtml

The umbrella module; "most new code should inherit this module".

com.google.gwt.user.theme.clean.Clean

The Clean theme: a stylesheet linked into the host page

Also Standard, Chrome and Dark under com.google.gwt.user.theme.*.

com.google.gwt.i18n.I18N

Messages, Constants, locale handling

Listed explicitly by the archetype.

com.google.gwt.json.JSON

JSONParser, JSONObject and friends

Not part of User: see the pitfalls.

com.google.gwt.xml.XML

XML parsing and creation in the browser

Not part of User.

com.google.gwt.http.HTTP

RequestBuilder

Already inside User.

com.google.gwt.logging.Logging

Turns on client-side java.util.logging output through the gwt.logging.enabled property

Not part of User; configured with properties, see Logging.

com.google.gwt.resources.Resources

ClientBundle, CssResource

Already inside User through UI.

com.google.gwt.activity.Activity, com.google.gwt.place.Place, com.google.gwt.editor.Editor

Activities and Places, the Editor framework

Declared by the Bookshelf for clarity.

com.google.gwt.validation.Validation, com.google.gwt.junit.JUnit

Client-side bean validation; GWTTestCase support

JUnit is inherited from test modules only.

com.google.web.bindery.requestfactory.RequestFactory, com.google.web.bindery.autobean.AutoBean

RequestFactory and AutoBeans

The web.bindery packages are part of gwt-user.

Inheritance is transitive and idempotent: User brings Editor (through UI) and Activity brings Place, which is why removing the Bookshelf’s explicit Editor line, or its Place line, still compiled in the scratch runs. Declaring modules explicitly is still the better habit, because a project then keeps compiling if a library stops pulling a module in.

Source path, public path and super-source

The source path is the compiler’s view of "what may become JavaScript". The three source-like elements share the same filtering attributes, which follow Ant’s FileSet rules: includes, excludes, defaultexcludes (on by default), casesensitive, and nested <include>, <exclude> and (in the parser) <skip> elements:

<module>
  <inherits name="com.google.gwt.user.User" />

  <!-- translatable Java: only the client package, minus test doubles -->
  <source path="client" excludes="**/*Fake*.java" />
  <source path="shared" />

  <!-- static files: everything under public, except editor backups -->
  <public path="public" excludes="**/*.bak" />

  <!-- replacement implementations for classes the browser cannot compile -->
  <super-source path="super" />
</module>

Three rules to remember. First, path is relative to the package that holds the module file, and <source path=""> means the module’s own package. Second, declaring any <source> or <super-source> removes the implied client, so a module that declares only <source path="shared"/> no longer sees client. Third, a <super-source> replaces classes by name: the Bookshelf needs a checksum for cache keys, and the server implementation uses java.util.zip.CRC32, which GWT does not emulate. The shared source keeps the JVM version and a super-source supplies the browser one:

// bookshelf-shared/src/main/java/com/example/bookshelf/shared/Checksum.java (JVM, used by the server)
package com.example.bookshelf.shared;

import java.nio.charset.StandardCharsets;
import java.util.zip.CRC32;

public final class Checksum {
  private Checksum() {
  }

  public static long of(String text) {
    CRC32 crc = new CRC32();
    crc.update(text.getBytes(StandardCharsets.UTF_8));
    return crc.getValue();
  }
}

// bookshelf-shared/src/main/super/com/example/bookshelf/shared/Checksum.java (browser)
package com.example.bookshelf.shared;

public final class Checksum {
  private Checksum() {
  }

  public static long of(String text) {
    long hash = 0xcbf29ce484222325L;
    for (int i = 0; i < text.length(); i++) {
      hash ^= text.charAt(i);
      hash *= 0x100000001b3L;
    }
    return hash;
  }
}

Both files compile in the scratch Bookshelf and the browser build contains no reference to CRC32. Two caveats come from the guide: a super-source class is never used in development mode with the JVM classes (the JRE class always wins there), and a super-source is the mechanism GWT itself uses for its JRE emulation. The two versions above return different values for the same text, so such a result must never be compared across the client/server boundary; in a real project make the behaviour of both versions identical, or compute the value on one side only.

Entry points and the load order

An entry point is a class that implements com.google.gwt.core.client.EntryPoint and can be constructed without arguments; onModuleLoad() is called once the module and the outer document are ready. All entry points of a module, including those of inherited modules, are compiled into the same script and called in sequence. A module that is only a library (the Bookshelf’s Shared) declares none. A module that is loaded from a host page should have at least one, but the compiler does not check it: in the scratch runs, a module with no <entry-point> compiled successfully and simply did nothing in the browser, while a misspelled class name failed the compile:

[INFO] Compiling module com.example.bookshelf.slots.Slots
[INFO]    Finding entry point classes
[INFO]       [ERROR] Hint: Check that the type name 'com.example.bookshelf.slots.client.Slotz' is really what you meant
[INFO]       [ERROR] Hint: Check that your classpath includes all required source roots

Stylesheets and scripts

<stylesheet> and <script> are meant to let a reusable module bring its own CSS and JavaScript, so that "clients of your library have everything they need automatically by inheriting from your module". The stylesheet half works as documented. The Bookshelf’s public path holds bookshelf.css, the module links it, and the compiled bookshelf.nocache.js loads it next to the Clean theme’s gwt/clean/clean.css:

<public path="public" />
<stylesheet src="bookshelf.css" />

The script half does not work with the default linker. The guide’s page still says scripts "will be loaded when your application starts", but the xsiframe linker, which is the default, refuses them. This is the exact error from the scratch build with <script src="stats-stub.js" /> in the module:

[ERROR] The Cross-Site-Iframe linker does not support <script> tags in the gwt.xml files, but the gwt.xml file (or the gwt.xml files which it includes) contains the following script tags:
stats-stub.js
In order for your application to run correctly, you will need to include these tags in your host page directly. In order to avoid this error, you will need to remove the script tags from the gwt.xml file, or add this property to the gwt.xml file: <set-configuration-property name='xsiframe.failIfScriptTag' value='FALSE'/>

With xsiframe.failIfScriptTag set to FALSE the build passes, the log says Ignoring the following script tags in the gwt.xml file, and the script is still copied to the output directory but never loaded. The reliable approach is to put a <script> element in the host page, before the selection script, and keep third-party scripts out of the module.

Servlets

<servlet path="/catalog" class="..."/> mounted a servlet inside the embedded development server. The guide itself notes that since GWT 1.6 the element no longer loads servlets in development mode and a WEB-INF/web.xml must do it; since GWT 2.13 the development server serves only static files at all. Declare servlets in web.xml (or with annotations) of the server module. The Bookshelf maps its RPC servlet to the module-relative path that @RemoteServiceRelativePath("catalog") produces:

<servlet>
  <servlet-name>catalogServlet</servlet-name>
  <servlet-class>com.example.bookshelf.server.CatalogServiceImpl</servlet-class>
</servlet>
<servlet-mapping>
  <servlet-name>catalogServlet</servlet-name>
  <url-pattern>/bookshelf/catalog</url-pattern>
</servlet-mapping>

Properties and configuration properties

<set-property>, <extend-property> and <set-configuration-property> all work on named properties, but they are different kinds. Deferred-binding properties (locale, user.agent) have a set of values and each combination is a permutation, so <extend-property> and <set-property> change what is compiled. Configuration properties (CssResource.enableGss, xsiframe.failIfScriptTag) are plain compile-time settings with no permutations. A <set-configuration-property> for a name that was never defined is tolerated for backwards compatibility but logs a warning, and one for a name that is a binding property is an error. The property names GWT itself defines are documented on the pages that own them.

Linkers

The linker decides what files the compiler writes and what the bootstrap script does. <add-linker name="..."/> picks one by name. There are three categories: pre-linkers run before the primary linker, there is exactly one primary linker (the last one added wins), and post-linkers run after it. xsiframe is the default; sso produces a single JavaScript file; std and xs are deprecated in favour of xsiframe (the bootstrap and the linkers are the subject of Linkers & Bootstrap). Adding sso to the one-permutation slots module replaced the whole output with two files, a single script of about 39 KB and the clear.cache.gif image, and no .cache.js file or .devmode.js file:

<module>
  <inherits name="com.google.gwt.user.User" />
  <entry-point class="com.example.bookshelf.slots.client.Slots" />
  <set-property name="user.agent" value="gecko1_8" />
  <set-property name="locale" value="default" />
  <add-linker name="sso" />
</module>

A single-script build needs a single permutation, which is why the example pins the properties. Custom linkers are registered with <define-linker name="short" class="..."/> and then added the same way.

Collapsing permutations

A permutation exists for every combination of values of the deferred-binding properties. The collapse elements tell the compiler that some values do not need separate code. They are absent from the Developer Guide; the parser (ModuleDefSchema) accepts <collapse-property name="..." values="..."/> and <collapse-all-properties/>, and GWT’s own mobile sample uses the first to collapse its custom formfactor property. The trade-off was measured on the Bookshelf client:

Module setting Permutations Observation

(none)

6

Six .cache.js files, each about 263 to 264 KB

<collapse-property name="user.agent" values="*"/>

3

One permutation per locale value

<collapse-all-properties/>

1

One .cache.js file of 330,775 bytes

<!-- merge the user.agent permutations: the app supports only two engines and treats them alike -->
<collapse-property name="user.agent" values="*" />

<!-- or: one permutation for everything (a bigger script that holds the code for every locale) -->
<collapse-all-properties />

Collapsing trades a larger download for fewer compiles; the collapsed script has to contain the code for every value and choose at run time. Use it for properties that change little (a custom property you defined) and measure before using it on locale.

The module with Maven: templates, generated module and mainModule

With net.ltgt.gwt.maven:gwt-maven-plugin the module file in the source tree is a template (src/main/module.gwt.xml, with no package directories). The generate-module goal merges it with the dependencies and writes the real Name.gwt.xml into target/classes under the right package. Three things are added or changed: a rename-to from moduleShortName, an <inherits> for every direct dependency that is itself a GWT library (read from its META-INF/gwt/mainModule file), and, unless the template declares a <source> or <super-source>, the three lines <source path="client"/>, <source path="shared"/> and <super-source path="super"/>. This is what the plugin wrote for the Bookshelf after the shared module became a library (see the packaging section below), with the JSON, public path and stylesheet lines used in the experiments above and without the <script> experiment:

<module rename-to="bookshelf">
  <inherits name="com.example.bookshelf.Shared"/>
  <inherits name="com.google.gwt.user.User"/>
  <inherits name="com.google.gwt.user.theme.clean.Clean"/>
  <inherits name="com.google.gwt.i18n.I18N"/>
  <inherits name="com.google.gwt.json.JSON"/>
  <inherits name="com.google.gwt.place.Place"/>
  <inherits name="com.google.gwt.activity.Activity"/>
  <inherits name="com.google.gwt.editor.Editor"/>
  <source path="client"/>
  <public path="public"/>
  <stylesheet src="bookshelf.css"/>
  <entry-point class="com.example.bookshelf.client.App"/>
  <extend-property values="en" name="locale"/>
  <extend-property values="es" name="locale"/>
  <set-configuration-property name="CssResource.enableGss" value="true"/>
  <set-configuration-property name="CssResource.conversionMode" value="strict"/>
</module>

The first <inherits> line was not in the template; it was generated from the mainModule file of the shared dependency. The POM supplies the two names the plugin needs:

<plugin>
  <groupId>net.ltgt.gwt.maven</groupId>
  <artifactId>gwt-maven-plugin</artifactId>
  <configuration>
    <moduleName>com.example.bookshelf.App</moduleName>
    <moduleShortName>bookshelf</moduleShortName>
  </configuration>
</plugin>

Setting skipModule to true disables the generation, for a hand-written module. The gwt-app and gwt-lib packagings (the parent POM enables the plugin with <extensions>true</extensions>) bind generate-module to generate-resources.

The host page, the selection script and the bootstrap

A host page is any HTML page that loads a module with a <script> tag pointing at the module’s nocache.js. The guide’s point is that it can be static, generated by a servlet, or part of an existing site. The Bookshelf’s host page, generated by the archetype, has no visible content at all; the GWT application fills the body:

<!doctype html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Bookshelf</title>
    <meta name="gwt:property" content="locale=en">
    <script src="bookshelf/bookshelf.nocache.js"></script>
  </head>
  <body>
    <noscript>Bookshelf needs JavaScript.</noscript>
  </body>
</html>

The guide’s older example also includes a hidden history <iframe> (with the id __gwt_historyFrame) "to enable full GWT history support". The archetype’s host page has no such iframe and the Places and history setup of the Bookshelf works without it, so do not add it to a new page. The language="javascript" attribute on the script tag is likewise historical.

What the compiler writes

For the bookshelf module the compiler wrote this directory, one script per permutation plus the bootstrap script. The slots module, with one permutation, wrote the minimal version:

bookshelf-slots/target/bookshelf-slots-1.0-SNAPSHOT/slots/
  slots.nocache.js          the selection script: tiny, never cache it
  D52ACBCEFCC3D2F2D57EF9FE48FA3E07.cache.js   the compiled application, named by content hash
  slots.devmode.js          bootstrap helper used by development mode
  clear.cache.gif           1x1 image used by the bootstrap
  compilation-mappings.txt  lists, for each .cache.js file, the property values it serves

bookshelf-client/target/bookshelf-client-1.0-SNAPSHOT/bookshelf/   (additional files)
  <hash>.gwt.rpc            GWT-RPC serialization policy files
  deferredjs/<hash>/1.cache.js, 2.cache.js   code-split fragments
  gwt/clean/clean.css       files from the public path of the Clean theme
  bookshelf.css, covers/    this module's public path

The FAQ still describes .cache.html files loaded into a hidden iframe; with the default linker of 2.13.1 the permutation files are .cache.js. The principle in the FAQ is current: the nocache.js file is regenerated under the same name on every compile, so it must not be cached by browsers or proxies, while the content-hashed files can be cached for a long time.

The bootstrap sequence

The selection script is where deferred binding is resolved in the browser. It reads the gwt:property meta tags, runs the property providers (for example the locale and user.agent ones), looks up the permutation that matches the values, and fetches that one script:

sequenceDiagram participant B as Browser participant H as Host page participant N as bookshelf.nocache.js participant C as hash.cache.js B->>H: GET index.html H-->>B: script tag for the selection script B->>N: GET bookshelf/bookshelf.nocache.js N->>N: read gwt:property meta tags, run property providers N->>C: GET the permutation for locale and user agent C-->>B: compiled application B->>B: wait for the document, then call every entry point

Two points follow from the guide’s bootstrap analysis. Put the selection script tag early in the page, because the compiled script is fetched asynchronously and it blocks no other script. And external <script> tags are guaranteed to have finished loading when onModuleLoad runs, while <img> tags are not.

gwt:property meta tags

A <meta name="gwt:property" content="name=value"> tag in the host page sets the value of a deferred-binding property for that page load, which is the standard way to pick a locale for a page. Because the selection script does the reading, the tag must appear in the page, not in the module XML. The runtime source of the script gives the full set of meta names it understands: gwt:property, gwt:onPropertyErrorFn and gwt:onLoadErrorFn, and each can be limited to one module by prefixing the name with the module name and two colons (bookshelf::gwt:property), which matters when two modules share a page. In the Bookshelf, the tag locale=en sets English for the page, while the URL parameter ?locale=es takes priority over the meta tag, as the locale.queryparam configuration property (default locale) says:

<meta name="gwt:property" content="locale=en">
<meta name="bookshelf::gwt:onLoadErrorFn" content="reportBookshelfLoadError">

Internationalization covers the locale property in depth. The value in a gwt:property tag must be one of the values the module allows; a function named in a gwt:onPropertyErrorFn tag is the hook for reporting a bad value.

RootPanel and RootLayoutPanel

Every widget must ultimately be attached to a root. There are two roots and the choice decides how the page is laid out.

RootPanel is "the panel to which all other widgets must ultimately be added". RootPanel.get() wraps the <body>, and RootPanel.get("some-id") wraps any element of the host page that has that id, which is how a GWT module is added to part of an existing page. Widgets in a RootPanel are laid out in natural HTML order. get(id) returns null when there is no such element.

RootLayoutPanel is the root for layout panels (DockLayoutPanel, SplitLayoutPanel and friends). Its get() is always attached to the body, there is no way to get one for another element (because resize events are only available for the window), and it resizes its child with the window. It works only in standards mode, which means the host page needs a <!doctype html> declaration. The Bookshelf shell is a DockLayoutPanel, so it goes into RootLayoutPanel; the "slots" variant adds two widgets to elements of a server-rendered page.

// Whole-window application: the Bookshelf shell (client package)
RootLayoutPanel.get().add(shell);

// Embedded widgets: the slots module (client package)
public class Slots implements EntryPoint {
  @Override
  public void onModuleLoad() {
    Label count = new Label("25 books");
    Button reload = new Button("Reload");
    reload.addClickHandler(event -> count.setText("Reloaded"));
    RootPanel.get("book-count").add(count);
    RootPanel.get("book-actions").add(reload);
  }
}

The host page for the slots module is an ordinary HTML page with ids. After the page loaded in a browser, the body contained:

<h1>Bookshelf</h1>
<p>In stock: <span id="book-count"><div class="gwt-Label">25 books</div></span></p>
<div id="book-actions"><button type="button" class="gwt-Button">Reload</button></div>

The browser output shows a weakness of the example: a Label renders as a <div>, which is not valid inside a <span>. Use a <div> or <span> slot that matches the widget (InlineLabel renders a <span>). Do not mix the two roots for one layout: a layout panel placed in a plain panel such as SimplePanel renders with zero height (see the pitfalls).

Packaging reusable libraries

A reusable GWT library is a module with an XML file and the Java sources next to the compiled classes, because the GWT compiler compiles from source, not from bytecode. In the old Ant-based days that meant putting the .java files into the JAR by hand. With the gwt-maven-plugin the gwt-lib packaging does it: the JAR it produces holds the module definition (generated), the .java sources, the .class files, the other resources, and an optional META-INF/gwt/mainModule file that tells downstream projects which module to inherit.

Item in the gwt-lib JAR Role

<slashified moduleName>.gwt.xml

Module definition, generated by gwt:generate-module

META-INF/gwt/mainModule

Generated by gwt:generate-module-metadata; makes generate-module in downstream projects add the <inherits> automatically

**/*.java

Sources used later by gwt:compile, gwt:devmode and gwt:codeserver

**/*.class

Compiled classes, used by the server and by JVM tests

other resources

*.gss, *.png, *.ui.xml and so on

The archetype leaves bookshelf-shared as a plain jar with a separate sources classifier JAR that the client depends on (maven-source-plugin). That works, with a trap: the sources JAR exists only after the package phase, so mvn test -pl bookshelf-client -am fails, in the scratch app, with No source code is available for type com.example.bookshelf.shared.Book; did you forget to inherit a required module?. Moving the shared module to gwt-lib removes both the trap and the extra dependency:

<!-- bookshelf-shared/pom.xml -->
<artifactId>bookshelf-shared</artifactId>
<packaging>gwt-lib</packaging>

<dependencies>
  <dependency>
    <groupId>org.gwtproject</groupId>
    <artifactId>gwt-servlet-jakarta</artifactId>
    <scope>provided</scope>
  </dependency>
  <dependency>
    <groupId>org.gwtproject</groupId>
    <artifactId>gwt-user</artifactId>
    <scope>provided</scope>
  </dependency>
</dependencies>

<build>
  <plugins>
    <plugin>
      <groupId>net.ltgt.gwt.maven</groupId>
      <artifactId>gwt-maven-plugin</artifactId>
      <configuration>
        <moduleName>com.example.bookshelf.Shared</moduleName>
        <relocateSuperSource>true</relocateSuperSource>
      </configuration>
    </plugin>
  </plugins>
</build>
<!-- bookshelf-shared/src/main/module.gwt.xml -->
<module>
  <inherits name="com.google.gwt.user.User" />
  <source path="shared" />
  <super-source path="super" />
</module>

The contents of the resulting JAR in the scratch build (abridged):

META-INF/gwt/mainModule
com/example/bookshelf/Shared.gwt.xml
com/example/bookshelf/shared/Book.java
com/example/bookshelf/shared/Book.class
com/example/bookshelf/shared/Checksum.java
com/example/bookshelf/shared/Checksum.class
com/example/bookshelf/super/com/example/bookshelf/shared/Checksum.java

The client dependency is now the plain artifact (no sources classifier), the module gets <inherits name="com.example.bookshelf.Shared"/> automatically, and the server module depends on the same JAR for the JVM classes. relocateSuperSource is the detail to remember: the add-super-sources goal adds src/main/super as a resource directory, and only with relocateSuperSource set (and moduleName known) does it place the content under a super sub-folder of the module package. Without it, the shared JAR contained no super/ entries and the client compile failed with the error shown in the table below.

A library should follow four habits. Ship sources and module together. Inherit only the modules you use, so that a consumer is not forced into extra permutations. Declare the library’s own <stylesheet> and public path in its module, so that inheriting it is enough. And keep the public package names stable, because the module’s logical name is part of its API.

Worked example: the Bookshelf, end to end

The pieces above fit together as follows when the Bookshelf is built with mvn package:

Maven module Packaging and module What it produces

bookshelf-shared

gwt-lib, module com.example.bookshelf.Shared

JAR with module, sources, classes and mainModule; used by client (as source) and server (as classes)

bookshelf-client

gwt-app, module com.example.bookshelf.App, renamed bookshelf

WAR-shaped directory with bookshelf/bookshelf.nocache.js and the permutation scripts; no Java classes or web.xml

bookshelf-server

war

Servlets, WEB-INF/web.xml, the host page index.html; overlays the client output so that the module is served from /bookshelf/

The build that was run for this page, with JDK 21 and Maven 3.9, was mvn -B package -DskipTests (the first compile of the client took about 20 seconds for six permutations). Run the client alone with the dependencies it needs by naming the module, not with a wildcard:

mvn -B package -DskipTests -pl bookshelf-client -am

The -pl '*-client' wildcard that appears in some guides is a Maven 4 feature and fails on Maven 3.9 with Could not find the selected project in the reactor: *-client.

Pitfalls

Symptom (exact message) Cause Fix

No source code is available for type com.example.bookshelf.shared.Book; did you forget to inherit a required module?

A class used by client code is not on any source path: the shared package is not declared with <source path="shared"/>, or the library that holds it is not inherited.

Add the <source> element, or <inherits> the library module. With the plugin, check that the dependency is a gwt-lib or has a sources JAR on the classpath.

No source code is available for type com.google.gwt.json.client.JSONObject; did you forget to inherit a required module? (also for JSONParser)

A GWT module that is not part of User is used without being inherited.

<inherits name="com.google.gwt.json.JSON"/> (and com.google.gwt.xml.XML for the XML classes).

No source code is available for type java.util.zip.CRC32; did you forget to inherit a required module?

The class is not emulated and no super-source replaces the class that uses it; or the shared JAR was built without relocateSuperSource, so the replacement is missing from it.

Provide a <super-source> class and set relocateSuperSource to true for the library; or avoid the JDK class on the client.

mvn test -pl bookshelf-client -am fails with the "No source code is available" message for a shared class

The shared module is a plain JAR whose sources classifier JAR is produced only at package.

Use mvn verify, or make the shared module a gwt-lib.

The Cross-Site-Iframe linker does not support <script> tags in the gwt.xml files ...

A <script src> in a module and the default xsiframe linker.

Put the <script> in the host page; xsiframe.failIfScriptTag set to FALSE only hides the problem (the tag is ignored).

Finding entry point classes followed by Hint: Check that the type name '...Slotz' is really what you meant

<entry-point class> misspelled or not on the source path.

Fix the name; check the package is under a <source> path.

The module compiles and the page stays blank, no error

The module has no <entry-point>, or the host page loads the wrong nocache.js path (after rename-to changes), or the script is cached.

Add the entry point; the script URL is <rename-to>/<rename-to>.nocache.js; do not cache nocache.js.

NPE in onModuleLoad when using RootPanel.get("book-count")

RootPanel.get(id) returns null when no element with that id exists.

Check the host page, or null-check and fail with a clear message.

Blank screen: RootLayoutPanel added and nothing visible, or a DockLayoutPanel with zero height

The host page lacks <!doctype html> (layout panels need standards mode), or the layout panel sits in a plain panel with no size.

Add the doctype; use RootLayoutPanel or a SimpleLayoutPanel as the parent.

Uncaught ReferenceError: code is not defined in the console and the module never starts

A permutation file (<hash>.cache.js) is missing from the module directory that the server publishes, for example because only the nocache.js file or a hand-picked part of the directory was deployed, and the default obfuscated xsiframe output is used. The gwt:onLoadErrorFn hook is not called in this case.

Publish the whole module directory of the compile; see Linkers & Bootstrap for the failure, the startup events to watch instead of the hook, and the other output styles.

A static file returns 404

It is outside the public path, or <public> declared elsewhere removed the implied public, or the URL ignores the module base.

Put it in the public path; build the URL with GWT.getModuleBaseForStaticFiles().

[WARNING] Ignoring incompatible plugin version 4.0.0-beta-3

Maven 3.9 skipping beta plugin versions that need Maven 4 while resolving the install and deploy plugins.

Noise; ignore.

-pl '*-client': Could not find the selected project in the reactor

Wildcards in -pl need Maven 4.

Use -pl bookshelf-client.

Where the older material is outdated

  • The Developer Guide’s standard-module table (GWT 1.5) lists five modules and three themes; the 2.13.1 gwt-user has many more, and User is a large umbrella (see the table above).

  • The guide’s working-module example pins user.agent to ie6; in 2.13.1 the values are gecko1_8 and safari.

  • The guide’s <script> description predates the xsiframe default linker, which rejects the element.

  • The guide’s <servlet> description (embedded server) and the webAppCreator and Ant directory layout describe tooling that is gone; the 2.12.0 release notes list the removal of the ApplicationCreator and ProjectCreator main classes.

  • The FAQ describes .cache.html files and an iframe bootstrap; the default linker now writes .cache.js files.

  • The 2007 book GWT in Action (Hanson and Tacy) introduces modules, the host page and packaging modules as JARs with GWT 1.x tools (the applicationCreator tool, hosted mode). The concepts of module inheritance, source and public paths and entry points carry over; the commands, the file layout and the property values do not. Use this page and the official guide for current syntax.