GWT Maven Plugin
GWT Maven Plugin
......................................................................................................................................
Codehaus 2009-10-14
Table Of Content i
Table Of Content
.......................................................................................................................................
1 Back to Mojo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2 Version 1.0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3 Version 1.1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4 Download as PDF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5 Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
6 Goals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7 Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
8 GWT 2.0 preview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
9 FAQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
10 Eclipse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
11 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
12 Setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
13 the /war folder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
14 Using the archetype . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
15 Run Hosted Mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
16 Generate Async . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
17 Internationalization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
18 Testing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
19 Compile and Package . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
20 Multi-project setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
21 Writing a GWT library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
22 Productivity Tip . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
23 compile a GWT module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
24 generate async interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
25 generate i18n bundles interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
1 Index
.......................................................................................................................................
• Testing Support
• Hosted server Configuration
• Using the Archetype
1.1.3 History
GWT-maven plugin has merged with this plugin since version 1.1
version 1.2 includes a preview of gwt 2.0 support
2 Usage
.......................................................................................................................................
<project>
[...]
<build>
<plugins>
[...]
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>gwt-maven-plugin</artifactId>
<version>1.1</version>
<configuration>
<module>com.mycompany.gwt.Module</module>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
[...]
</plugins>
</build>
[...]
</project>
You can also configure compilation for multiple modules by nesting them inside a '' modules''
element. If none is set, the plugin will scan project source and resources directories for ''.gwt.xml''
module files.
See user guide for more details.
<project>
[...]
<build>
<plugins>
[...]
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>gwt-maven-plugin</artifactId>
<version>1.1</version>
<configuration>
<servicePattern>**/gwt/**/*Service.java</servicePattern>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>generateAsync</goal>
</goals>
</execution>
</executions>
</plugin>
[...]
</plugins>
</build>
[...]
</project>
<project>
[...]
<build>
<plugins>
[...]
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>gwt-maven-plugin</artifactId>
<version>1.1</version>
<configuration>
<i18nMessagesBundle>com.mycompany.MyApp</i18nMessagesBundle>
</configuration>
<executions>
<execution>
<goals>
<goal>i18n</goal>
</goals>
</execution>
</executions>
</plugin>
[...]
</plugins>
</build>
[...]
</project>
<project>
[...]
<build>
<plugins>
[...]
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>gwt-maven-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<goals>
<goal>test</goal>
</goals>
</execution>
</executions>
</plugin>
[...]
</plugins>
</build>
[...]
</project>
This plugin declaration could be part of a profile, so that it gets only enabled on continuous
integration server, as such test execution is long and will penalize the developper.
See user guide for a detailled description of testing with GWT and Maven, and suggestion about
using GwtTestSuite.
3.2 Setup
As GWT 2.0 is not released, you'ill have to install a JDK preview. Set the plugin ''gwtHome''
parameter to point to this SDK, and configure a System dependency for the gwt-user API.
<properties>
<gwtHome>${basedir}/gwt-0.0.0-6120</gwtHome>
</properties>
<dependencies>
<dependency>
<groupId>com.google.gwt</groupId>
<artifactId>gwt-user</artifactId>
<version>2.0-6120</version>
<scope>system</scope>
<systemPath>${gwtHome}/gwt-user.jar</systemPath>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>gwt-maven-plugin</artifactId>
<configuration>
<gwtHome>${gwtHome}</gwtHome>
<disableCastChecking>true</disableCastChecking>
<disableClassMetadata>true</disableClassMetadata>
</configuration>
<executions>
<execution>
<goals>
<goal>generateAsync</goal>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<reporting>
<excludeDefaults>true</excludeDefaults>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>gwt-maven-plugin</artifactId>
<reportSets>
<reportSet>
<reports>
<report>soyc</report>
</reports>
</reportSet>
</reportSets>
<configuration>
<gwtHome>${gwtHome}</gwtHome>
</configuration>
</plugin>
</plugins>
</reporting>
4 FAQ
.......................................................................................................................................
4.1.3 How does this plugin compare to other maven / gwt plugins ?
This plugin, being part of the Mojo Project, can benefict for a large community of maven developers.
Its async interface generation feature is AFAIK not supported by other plugins.
5 Eclipse
.......................................................................................................................................
5.1.1 Limitations
A restriction of this plugin is that it will search for gwt modules and host pages only in the first
classpath source folder. Using a Maven / Eclipse integration like m2eclipse, this one will be your
sourceDirectory ( src/main/java). You'll have to move your gwt.xml files in this folder, instead of
the standard Maven resource directory. See Google Eclipse Plugin issue #1597
Another bigger restriction of this plugin, is that it requires the hosted mode webapp to use /war
directory as web application root. We will have to change the maven-war-plugin setup to use this
folder and not the default src/main/webapp path, but will keep the latest to host the web.xml
deployment descriptor. We can then have a dedicated hosted mode one where we register stub RPC-
servlets for testing purpose. The 'real' web application may be long to start and require more complex
resources, like a JDBC DataSource, and we can still run functionnal tests on it using the noserver
option. See Google Eclipse Plugin issue #1515
pom.xml
|_src
| |_main
| |_java
| | |_ com/mycompany/gwt/Module.gwt.xml
| | |_ com/mycompany/gwt/client
| | | |_ ModuleEntryPoint.java
| |_resources
| |_webapp
| |_WEB-INF
| |_web.wml
|_war
|_Module.html
|_WEB-INF
|_web.wml
The war folder will be used to host your test web application (used in hosted mode) where you'll put
stub RPC servlets. Your real web application can be used for more advanced integration testing with
the noserver option.
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany</groupId>
<artifactId>webapp</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>com.google.gwt</groupId>
<artifactId>gwt-user</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>gwt-maven-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
<configuration>
<runTarget>com.mycompany.gwt.Module/Module.html</runTarget>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.0.2</version>
<configuration>
<warSourceDirectory>war</warSourceDirectory>
<webXml>src/main/webapp/WEB-INF/web.xml</webXml>
</configuration>
</plugin>
</plugins>
</build>
</project>
With this setup, you can start your GWT module with a single right-clik in your Eclispe IDE with Run
as : Web application.
You can the edit your java code and just hit refresh to see changes applied in the hosted browser.
This one will be ignored after your GWT module has been compiled into JavaScript.
When using Eclipse-Maven integration like the m2eclipse plugin, other maven projects open in the
workspace will be automagically resolved as projects (instead of JARs). When the referenced project
is well configured(*) as a GWT module project, changes to java sources will be available in the
hosted browser with a simple refresh with no requirement to repackage the modules.
images/gwt-maven-logo.png
m2eclipse detecting the gwt module as project reference
(*) A " well configured GWT module project" is expected to have Java sources copied as
resources in the project build outputDirectory (using gwt:resource goal) and a dedicated
gwt.xml module file to define the required inherits.
The gwt-maven-plugin src/it/reactor project can be reviewed as a demonstrating
sample of this setup.
6 Introduction
.......................................................................................................................................
6.1 Introduction
This maven plugin is dedicated to the Google Web Toolkit integration in Maven.
Its primary goal is to run the GWT SDK tools from Maven. It uses Maven dependency management
feature to avoid manual installation of the GWT SDK on the developper platform. Importing a GWT-
based application as Mproject then requires no dedicated manual setup on the developer computer.
Its secondary goal is to nicely integrate with Eclipse and the Google Eclipse plugin. This has many
side effects as this plugin use some hard-coded path and conventions that are not Maven compliant as
is.
GWT Maven Plugin supports :
7 Setup
.......................................................................................................................................
<properties>
<gwt.version>1.6.4</gwt.version>
</properties>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>gwt-maven-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<goals>
<!-- gwt:* goals to be executed during build -->
</goals>
</execution>
</executions>
</plugin>
Note : Don't define gwt-dev as project dependency : this JAR has many common libraries
packaged that may conflict with the ones defined for your project, resulting in uncomprehensible
NoSuchMethodErrors. The gwt-maven-plugin will automagically resolve the required dependency
based on your declared gwt-user dependency.
<property>
<google.webtoolkit.home>C:/MyCustomGWT</google.webtoolkit.home>
</property>
You can also use the $ env.GWT_HOME syntax to refer to an OS environment variable.
For manual mode, you also need the GWT dependencies defined (these are required because plugins
and goals other than gwt-maven-plugin need them, like the standard compiler).
Note that with manual mode, even though the dependencies are still needed, the difference is that the
source of the dependencies can be your locally installed GWT location (GWT_HOME), rather than
a Maven repository, and there is no separate step to unpack the native libraries (they are already in
gwtHome).
For example:
<property>
<google.webtoolkit.home>${env.GWT_HOME}</google.webtoolkit.home>
</property>
<dependency>
<groupId>com.google.gwt</groupId>
<artifactId>gwt-servlet</artifactId>
<version>custom</version>
<scope>system</scope>
<systemPath>${env.GWT_HOME}/gwt-servlet.jar</systemPath>
</dependency>
<dependency>
<groupId>com.google.gwt</groupId>
<artifactId>gwt-user</artifactId>
<version>custom</version>
<scope>system</scope>
<systemPath>${env.GWT_HOME}/gwt-user.jar</systemPath>
</dependency>
. . . .
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>gwt-maven-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>generateAsync</goal>
</goals>
</execution>
</executions>
</plugin>
• the hosted mode will run the full web application, will all its frameworks, security and resources
constraints
• any change to a configuration file or java source will require the web application to be
repackaged using war:exploded
mvn archetype:generate \
-DarchetypeGroupId=org.codehaus.mojo \
-DarchetypeArtifactId=gwt-maven-plugin \
-DarchetypeVersion=1.1 \
-DgroupId=myGroupId \
-DartifactId=myArtifactId
Note: don't run mvn archetype:create as the plugin uses archetype NG descriptor.
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.1-beta-1</version>
<configuration>
<warSourceDirectory>war</warSourceDirectory>
</configuration>
</plugin>
11 Generate Async
.......................................................................................................................................
11.1.1 About
GWT client will communicate with server-side components using GWT-RPC data serialization
protocol. If you're not familiar with this please review the developper's guide.
The GWT-RPC model requires you to define two interfaces : one on server side to handle requests,
and a sibling one on client side for invoking the RPC serialization process. The second one is
asynchronous, and the two interfaces must match together.
Considering the following Remote Service interface :
import com.google.gwt.user.client.rpc.RemoteService;
@RemoteServiceRelativePath( "HelloWorld" )
public interface HelloWorldService
extends RemoteService
{
String helloWorld( String message );
}
gwt-maven-plugin includes a simple code generator to create all Async interfaces from your server-
side remote service interfaces.
<project>
[...]
<build>
<plugins>
[...]
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>gwt-maven-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<configuration>
<servicePattern>**/gwt/**/*Service.java</servicePattern>
</configuration>
<goals>
<goal>generateAsync</goal>
</goals>
</execution>
</executions>
</plugin>
[...]
</plugins>
</build>
[...]
</project>
This utility class must know the server URI the Remote Service is exposed. The plugin will use
@RemoteServiceRelativePath annotation on the service interface to set the URI in this utility
class. In previous example, the service will be binded to URI [module]/HelloWorld.
If no annotation is set, the service URI is constructed from interface name applying the rpcPattern
format. Setting this parameter to " .rpc" will create an Util class to bind the service to URI
[module]/HelloWorldService.rpc.
The generateAsync goal also has a failOnError parameter that can be helpfull is you have issue
with the generator.
12 Internationalization
.......................................................................................................................................
12.1.1 About
GWT uses standard java message bundles for internationalization (i18n), but use the compile-time
multiple-permutation strategy to create a JavaScript output file per supported language. On client-side
code, developers use Message interface to read String from the bundle. Such interfaces are generated
by a SDK tool.
If you're not familiar with this please review i18n interfaces generator documentation.
<project>
[...]
<build>
<plugins>
[...]
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>gwt-maven-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<goals>
<goal>i18n</goal>
</goals>
</execution>
</executions>
<configuration>
<resourceBundle>com.mycompany.gwt.Bundle</resourceBundle>
</configuration>
</plugin>
[...]
</plugins>
</build>
[...]
</project>
<project>
[...]
<build>
<plugins>
[...]
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>gwt-maven-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<goals>
<goal>i18n</goal>
</goals>
</execution>
</executions>
<configuration>
<resourceBundles>
<resourceBundle>com.mycompany.gwt.Bundle1</resourceBundle>
<resourceBundle>com.mycompany.gwt.Bundle2</resourceBundle>
<resourceBundle>...</resourceBundle>
</resourceBundles>
</configuration>
</plugin>
[...]
</plugins>
</build>
[...]
</project>
13 Testing
.......................................................................................................................................
<project>
[...]
<build>
<plugins>
[...]
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>gwt-maven-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<goals>
<goal>test</goal>
</goals>
</execution>
</executions>
</plugin>
[...]
</plugins>
</build>
[...]
</project>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.4.3</version>
<configuration>
<excludes>
<exclude>**/*GwtTest.java</exclude>
</excludes>
</configuration>
</plugin>
A simplier way to separate classic and GWT tests is to name latests GwtTest"Something.java
- they start with "GwtTest". Surefire looks for tests that are named Something"Test".java by
default - they end with "Test".
By default, the gwt-maven-plugin uses GwtTest*.java as inclusion pattern so that GwtTest
will not match the standard Surefire pattern. Using this convention you don't have to change your
configuration.
To configure the plugin to use such a naming convention, set the includes plugin parameter.
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>gwt-maven-plugin</artifactId>
<version>1.1</version>
<configuration>
<includes>**/CustomPattern*.java</includes>
</configuration>
<executions>
<execution>
<goals>
<goal>test</goal>
</goals>
</execution>
</executions>
</plugin>
start with GwtTest, and does not start or end with Test. For example MyClassTestGwt.java.
This way, gwt-maven-plugin picks up the Suite, and runs it, but does not also run individual tests
(and Surefire does not pick it up either)
<project>
[...]
<build>
<plugins>
[...]
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>gwt-maven-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<id>test</id>
<goals>
<goal>test</goal>
</goals>
<phase>test</phase>
</execution>
</executions>
</plugin>
[...]
</plugins>
</build>
[...]
</project>
<project>
[...]
<build>
<plugins>
[...]
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>gwt-maven-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<configuration>
<module>com.mycompany.gwt.Module</module>
</configuration>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
[...]
</plugins>
</build>
[...]
</project>
-Dgwt.logLevel=[LOGLEVEL]
Where LOGLEVEL can be ERROR, WARN, INFO, TRACE, DEBUG, SPAM, or ALL
The compiler style is set to its default value ( OBFUSCATED) to generate compact javascript. You
can override this for debugging purpose of the generated javascript by running with command line
option :
-Dgwt.style=[PRETTY|DETAILED]
The compiler will output the generated javascript in the project output folder ( $
project.build.directory/$ project.build.finalName). For a WAR project, this matches
the exploded web application root. You can also configure the plugin to compile in $ basedir/
src/main/webapp that may better match using lightweight development process based on to the
"inplace" mode of the war plugin. To enable this, just set the inplace parameter to true.
<project>
[...]
<build>
<plugins>
[...]
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>gwt-maven-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<configuration>
<extraJvmArgs>-Xmx512M -Xss1024k</extraJvmArgs>
</configuration>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
[...]
</plugins>
</build>
[...]
</project>
Inplace use the web application source directory src/main/webapp as output folder. to match
the war:inplace goal. This one setup an explosed WAR structure in the source folder for rapid JEE
development without the time-consuming package/deploy/restart cycle.
Using this folder is also very usefull for those of us that run a server using tomcat:run or jetty:run
goals. Those plugins don't require any packaging to launch the webapp, and handle nicelly Maven
dependencies and classes without requirement for a WEB-INF/lib and WEB-INF/classes. With
this default GWTCompiler output directory, the application can be run as is with no packaging
requirement.
15 Multi-project setup
.......................................................................................................................................
------ GWT in a multi-project setup ------ Stefan Hübner ([email protected]) ------
15.1.1 Introduction
In Maven sub projects are called modules. Maven-modules support the concept of project
aggregation. In the context of a GWT application, like in a normal web application, a common
example could be to separate GUI functionality from domain functionality (among others).
We will use this plugin's reactor it-test as a sample project layout (note: this is not a comprehensive
example. It just demonstrates the basic principles):
The reactor project contains two subprojects - jar and war. jar contains a Domain GWT module
consisting of it's module descriptor Domain.gwt.xml and a User class. The war subproject contains
another GWT module called Hello consisting of it's module descriptor Hello.gwt.xml and a
Hello class.
NOTE that GWT also has a notion of module. Both Maven and GWT use the term module to
define units of modularization. To a degree both concepts go hand in hand, as GWT-modules define
boundaries at which Maven-modules might be cut. To not confuse these two terms though, for the rest
of this section we will use the term module, if we talk about GWT-modules, in contrast to the term
project, if we talk about Maven-modules.
package org.codehaus.mojo.gwt.test.domain;
public class User
{
public String sayHello()
{
return "Hello";
}
}
<module>
<inherits name="com.google.gwt.user.User"/>
<source path="domain"/>
</module>
The last step is to setup the pom.xml. Please note the special build/resources declaration:
<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.o
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.codehaus.mojo.gwt.it</groupId>
<artifactId>reactor</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>domain</artifactId>
<packaging>jar</packaging>
<build>
<!--
sources need to be bundled with the jar,
so they are visible to GWT's compiler
-->
<!--
You can either setup a resource to point to your java sources ...
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.java</include>
<include>**/*.gwt.xml</include>
</includes>
</resource>
</resources>
-->
<plugins>
<!--
... or ask the plugin to detect them based on gwt modules files and copy the
-->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>gwt-maven-plugin</artifactId>
<executions>
<!-- GWT version detected from dependencyManagement -->
<execution>
<goals>
<goal>resources</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Sources need to be bundled with the JAR in order for the GWT compiler to be able to compile them
during reactor build.
Next is to setup the war subproject.
package org.codehaus.mojo.gwt.test.client;
import org.codehaus.mojo.gwt.test.domain.User;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
public class Hello
implements EntryPoint
{
final HelloServiceAsync service = HelloServiceAsync.Util.getInstance();
public void onModuleLoad()
{
User user = new User();
final Label l = new Label( "GWT says : " + user.sayHello() );
RootPanel.get().add( l );
Button b = new Button( "click me !" );
RootPanel.get().add( b );
b.addClickHandler( new ClickHandler()
{
public void onClick( ClickEvent event )
{
service.sayHello( "hello", new AsyncCallback<String>()
{
public void onFailure( Throwable caught )
{
l.setText( "RPC failure " + caught.getMessage() );
GWT.log( "RPC failure", caught );
}
public void onSuccess( String result )
{
l.setText( result );
}
} );
}
} );
}
}
It calls Domain's User class and displays the result in the root panel.
Next is to setup GWT module org.codehaus.mojo.gwt.test.Hello. The important thing to
note is that this module inherits the Domain module:
<module>
<inherits name="com.google.gwt.user.User"/>
<inherits name='com.google.gwt.user.theme.standard.Standard'/>
<inherits name="org.codehaus.mojo.gwt.test.Domain"/>
<entry-point class="org.codehaus.mojo.gwt.test.client.Hello"/>
<servlet class="org.codehaus.mojo.gwt.test.server.HelloRemoteServlet" path="/org.c
</module>
Finally, in the war's POM a dependency to the jar-artifact will be declared and the gwt-maven-
plugin needs to be setup:
<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.o
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.codehaus.mojo.gwt.it</groupId>
<artifactId>reactor</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>webapp</artifactId>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>com.google.gwt</groupId>
<artifactId>gwt-user</artifactId>
<scope>provided</scope>
</dependency>
<!-- this is the dependency to the "jar"-subproject -->
<dependency>
<groupId>org.codehaus.mojo.gwt.it</groupId>
<artifactId>domain</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>gwt-maven-plugin</artifactId>
<executions>
<!-- GWT version detected from dependencyManagement -->
<execution>
<goals>
<goal>compile</goal>
<goal>generateAsync</goal>
</goals>
</execution>
</executions>
<configuration>
<runTarget>org.codehaus.mojo.gwt.test.Hello/Hello.html</runTarget>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.0.2</version>
<configuration>
<warSourceDirectory>war</warSourceDirectory>
<webXml>src/main/webapp/WEB-INF/web.xml</webXml>
</configuration>
</plugin>
</plugins>
</build>
</project>
Since the jar-dependency bundles it's sources, they will be visible to GWT's compiler.
<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.o
<modelVersion>4.0.0</modelVersion>
<groupId>org.codehaus.mojo.gwt.it</groupId>
<artifactId>reactor</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
<!-- you will need to replace this with the correct version -->
<gwtPluginVersion>@pom.version@</gwtPluginVersion>
<gwtVersion>1.6.4</gwtVersion>
</properties>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>gwt-maven-plugin</artifactId>
<version>${gwtPluginVersion}</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.1-alpha-2</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.google.gwt</groupId>
<artifactId>gwt-user</artifactId>
<version>${gwtVersion}</version>
<scope>provided</scope>
</dependency>
</dependencies>
</dependencyManagement>
<modules>
<module>jar</module>
<module>war</module>
</modules>
</project>
16.1.1 Packaging
The only distinction with a standard JAR project is the mix of sources and classes in the output folder.
A simple way to achieve this is to add a dedicated resource in the POM :
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.java</include>
<include>**/*.gwt.xml</include>
</includes>
</resource>
</resources>
Another option is to let the plugin detect the required source to be included, based on the module
descriptor. The benefict is that the plugin will not include java files that are not declared as GWT
source by the module descriptor, avoiding end-user to reference your internal classes (usually for
library that include both client and server side components).
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>gwt-maven-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<goals>
<goal>resources</goal>
</goals>
</execution>
</executions>
</plugin>
17 Productivity Tip
.......................................................................................................................................
17.1.1 Introduction
Consider the following project setup
• At least my IDE (Netbeans) cannot have two open projects that share the same source path. The
api module will loose its src/java in the user interface, and the gui will get one ekstra "generated
sources" path, this is quite annoying.
• Because there is no guarantee on how the developer will checkout the code, the gui's pom cannot
guess where the api's src/main/java is on the disk.
17.1.3 Solution
The solution to those two issues is to create a profile in your pom (or settings.xml) which is only
activated when you run the gwt:run target :
<profile>
<id>dev</id>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.4</version>
<executions>
<execution>
<id>add-source</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>../api/src/main/java</source>
</sources>
</configuration>
</execution>
<execution>
<id>add-resource</id>
<phase>generate-sources</phase>
<goals>
<goal>add-resource</goal>
</goals>
<configuration>
<resources>
<resource>
<directory>../api/src/main/resources</directory>
<targetPath>resources</targetPath>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
You can then test in development mode and edit files in multible projects by running:
mvn gwt:run -Pdev
In Netbeans it is possible to save such a run target in the user interface.
<project>
[...]
<build>
<plugins>
[...]
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>gwt-maven-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<configuration>
<module>com.mycompany.gwt.Module</module>
</configuration>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
[...]
</plugins>
</build>
[...]
</project>
You can also configure compilation for multiple modules by nesting them inside a <modules>
element. If none is set, the plugin will scan project source and resources directories for .gwt.xml
module files.
<project>
[...]
<build>
<plugins>
[...]
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>gwt-maven-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<configuration>
<modules>
<module>com.mycompany.gwt.Module1</module>
<module>com.mycompany.gwt.Module2</module>
<module>...</module>
</modules>
</configuration>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
[...]
</plugins>
</build>
[...]
</project>
You can also ignore the ''module'' parameter, so that the plugin will scan your project for gwt.xml
module files.
By default, the GWT compiler is run with WARN logging. If you have compilation issues, you may
want it to be more verbose. Simply add a command line option:
-Dgwt.logLevel=[LOGLEVEL]
Where LOGLEVEL can be ERROR, WARN, INFO, TRACE, DEBUG, SPAM, or ALL.
The compiler style is set to its default value ( OBFUSCATED) to generate compact javascript. You
can override this for debugging purpose of the generated javascript by running with command line
option :
-Dgwt.style=[PRETTY|DETAILED]
The compiler will output the generated javascript in the project output folder ( $
project.build.directory/$ project.build.finalName). For a WAR project, this matches
the exploded web application root. You can override this behaviour by setting the ''outputDirectory''
parameter. For example, you may want to configure output to $ basedir/src/main/webapp if
you have configured your servlet container to use the "inplace" mode of the war plugin.
import com.google.gwt.user.client.rpc.RemoteService;
public interface HelloWorldService
extends RemoteService
{
String helloWorld( String message );
}
.. the plugin will automagically generate the asynchrounous interface used on client-side code. Thanks
to this feature, you don't have to write and maintain this boring code. As a bonus, the generated code
includes an utility class to retrieve the RPC proxy from client-side code:
@RemoteServiceRelativePath( "HelloWorld" )
public interface HelloWorldServiceAsync
{
String helloWorld( String message, AsyncCallBack<String> callback );
public static class Util
{
public static ContactPrefereServiceAsync getInstance()
...
}
}
The generated interface includes a nested Util class to help retrieve an HelloWorldServiceAsync
implementation.
The plugin will use @RemoteServiceRelativePath annotation on the service interface to set the
service URI in this utility class. In previous example, the service will be bound to URI [module]/
HelloWorld. If not present, the service URI is constructed from interface name applying the
rpcPattern format. Setting this parameter to " .rpc" will create an Util class to retrieve the
service on URI [module]/HelloWorldService.rpc.
To enable this feature, simply include the generateAsync goal in your POM.xml:
<project>
[...]
<build>
<plugins>
[...]
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>gwt-maven-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<goals>
<goal>generateAsync</goal>
</goals>
</execution>
</executions>
</plugin>
[...]
</plugins>
</build>
[...]
</project>
To avoid full scan of project sources, the plugin uses a naming convention for RPC services. By
default, it only checks **/*Service.java source files. You can override this convention using the
servicePattern parameter.
The rpcExtension is used to configure the URL pattern used on the server to publish the GWT-
RPC services. It will be used by the generator to create helper code (see later).
The failOnError parameter can also be helpfull if you have issue with the generator.
<project>
[...]
<build>
<plugins>
[...]
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>gwt-maven-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<goals>
<goal>i18n</goal>
</goals>
</execution>
</executions>
<configuration>
<i18nMessagesBundle>com.mycompany.gwt.Bundle</i18nMessagesBundle>
</configuration>
</plugin>
[...]
</plugins>
</build>
[...]
</project>
If your application uses more than one bundle, you can nest multiple i18nMessagesBundle
elements:
<project>
[...]
<build>
<plugins>
[...]
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>gwt-maven-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<goals>
<goal>i18n</goal>
</goals>
</execution>
</executions>
<configuration>
<i18nMessagesBundles>
<i18nMessagesBundle>com.mycompany.gwt.Bundle1</i18nMessagesBundle>
<i18nMessagesBundle>com.mycompany.gwt.Bundle2</i18nMessagesBundle>
<i18nMessagesBundle>...</i18nMessagesBundle>
</i18nMessagesBundles>
</configuration>
</plugin>
[...]
</plugins>
</build>
[...]
</project>
You can use the i18n goal to generate interfaces for either Messages, Constants and
ConstantsWithLookup interfaces, using the associated i18nMessagesBundles,
i18nConstantsBundles and i18nConstantsWithLookupBundles parameters