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.
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 |
|---|---|---|
|
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 ( |
|
Code used by both sides: DTOs, validators, the synchronous service interfaces, constants. Must stay inside the emulated JRE. |
Only when declared with |
|
Servlets, repositories, security filters. Anything that needs the full JDK. |
Never |
|
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
Source: GWT — Organizing Projects: Standard Directory and Package Layout, gwt-maven-plugin — Basic usage: Project layout
The same split, drawn as the three kinds of code and where each one is executed:
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 |
|---|---|---|
|
Root element. |
The guide names two uses: a short output directory (typical) and a "working module" that restricts permutations. The schema also accepts a |
|
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 |
|
Names a class that implements |
Several are allowed, also from inherited modules; they run in order of appearance, each after the previous |
|
Adds a sub-package (and its descendants) of the module’s package to the source path. |
If no |
|
Adds a sub-package to the public path: files there are copied to the module’s output directory. |
If no |
|
Re-roots a source path: the path prefix is stripped, so |
Declaring one also turns off the implied |
|
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. |
|
Injects an external JavaScript file before |
Not supported by the default |
|
Mounts a servlet for GWT’s embedded development server. |
The path must start with |
|
Fixes a deferred-binding property to a value, removing the other values (and so permutations). |
Example in the "working module" below. |
|
Adds allowed values to a property; accumulates through inheritance. |
The standard use is declaring locales. |
|
Sets a compile-time configuration property, such as |
A property that has no matching define is accepted for backwards compatibility but logs a warning. |
|
Selects a linker by its registered name. |
Additive for pre- and post-linkers; only the last primary linker is used. |
|
Merges permutations that differ only in the listed values of one deferred-binding property. |
The values must be ones previously defined for the property; |
|
Collapses every deferred-binding property, producing one permutation. |
Takes an optional |
|
Registers a resource path with the module. |
Accepted by the parser but not described in the guide, so avoid it. |
|
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 |
|---|---|---|
|
The |
Inherited implicitly by every module. |
|
Widgets, panels, events, HTTP, RPC support, timers, |
The umbrella module; "most new code should inherit this module". |
|
The Clean theme: a stylesheet linked into the host page |
Also |
|
|
Listed explicitly by the archetype. |
|
|
Not part of |
|
XML parsing and creation in the browser |
Not part of |
|
|
Already inside |
|
Turns on client-side |
Not part of |
|
|
Already inside |
|
Activities and Places, the Editor framework |
Declared by the Bookshelf for clarity. |
|
Client-side bean validation; |
|
|
RequestFactory and AutoBeans |
The |
Source: GWT — Organizing Projects: How do I know which GWT modules I need to inherit?, GWT 2.13.1 — User.gwt.xml
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>
Source: GWT — Linkers: usage
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 |
|
3 |
One permutation per locale value |
|
1 |
One |
<!-- 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>
Source: gwt-maven-plugin — Basic usage
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
Source: GWT — FAQ Debugging and Compiling: The .nocache.js File, gwt-maven-plugin — Artifact Handlers (gwt-app layout)
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:
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);
}
}
Source: GWT — Organizing Projects: HTML Host Pages (RootPanel.get), GWT Javadoc — RootPanel, GWT Javadoc — RootLayoutPanel
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 |
|---|---|
|
Module definition, generated by |
|
Generated by |
|
Sources used later by |
|
Compiled classes, used by the server and by JVM tests |
other resources |
|
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.
Source: gwt-maven-plugin — Artifact Handlers (gwt-lib), gwt-maven-plugin — gwt:add-super-sources, gwt-maven-plugin — gwt:generate-module-metadata, gwt-maven-plugin — gwt:package-lib
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 |
|---|---|---|
|
|
JAR with module, sources, classes and |
|
|
WAR-shaped directory with |
|
|
Servlets, |
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 |
|---|---|---|
|
A class used by client code is not on any source path: the |
Add the |
|
A GWT module that is not part of |
|
|
The class is not emulated and no super-source replaces the class that uses it; or the shared JAR was built without |
Provide a |
|
The shared module is a plain JAR whose |
Use |
|
A |
Put the |
|
|
Fix the name; check the package is under a |
The module compiles and the page stays blank, no error |
The module has no |
Add the entry point; the script URL is |
NPE in |
|
Check the host page, or null-check and fail with a clear message. |
Blank screen: |
The host page lacks |
Add the doctype; use |
|
A permutation file ( |
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 |
Put it in the public path; build the URL with |
|
Maven 3.9 skipping beta plugin versions that need Maven 4 while resolving the install and deploy plugins. |
Noise; ignore. |
|
Wildcards in |
Use |
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-userhas many more, andUseris a large umbrella (see the table above). -
The guide’s working-module example pins
user.agenttoie6; in 2.13.1 the values aregecko1_8andsafari. -
The guide’s
<script>description predates thexsiframedefault linker, which rejects the element. -
The guide’s
<servlet>description (embedded server) and thewebAppCreatorand Ant directory layout describe tooling that is gone; the 2.12.0 release notes list the removal of theApplicationCreatorandProjectCreatormain classes. -
The FAQ describes
.cache.htmlfiles and an iframe bootstrap; the default linker now writes.cache.jsfiles. -
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
applicationCreatortool, 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.
References
-
GWT Developer Guide — Organizing Projects (host page, package layout, modules, module XML, inheriting modules, resource inclusion, path filtering, bootstrap sequence)
-
GWT FAQ — Debugging and Compiling (the nocache.js file)
-
Hanson and Tacy, GWT in Action (Manning, 2007), consulted for chapters 2 and 9 only as historical background