Multi-Project Setup

Often, larger Maven projects will be divided into sub projects. How to use GWT-maven-plugin in such a setup is described in this section.

First, we will setup a basic Maven project structure consisting of two subprojects: one containing domain code and another one containing the actual GWT application. After this has been set up, we will see, how Maven packages the application using the GWT-maven-plugin.

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):

reactor/                                     (aggregating parent project)
|- pom.xml
|
|- jar/                                      (domain code, etc.; packaging: JAR)
|  |- pom.xml
|  \- src/main/java/
|     \- org/codehaus/mojo/gwt/test/
|        |- Domain.gwt.xml
|        \- domain/User.java
|
\- war/                                      (GUI code; packaging: WAR)
   |- pom.xml
   \- src/
      |- main/java/
      |  \ -org/codehaus/mojo/gwt/test/
      |     |- Hello.gwt.xml
      |     \- client/Hello.java
      \- main/webapp/
         \- WEB-INF/web.xml

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.

Necessary Steps

Subproject: jar

Here's how the jar subproject looks like. We'll define a org.codehaus.mojo.gwt.test.domain.User class:

package org.codehaus.mojo.gwt.test.domain;

public class User
{
    public String sayHello()
    {
        return "Hello";
    }
}

This class will be living in a GWT module called org.codehaus.mojo.gwt.test.Domain:

<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.org/maven-v4_0_0.xsd">
  <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 required java sources
        -->
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>gwt-maven-plugin</artifactId>
        <executions>
          <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.

Subproject: war

First, here's the class org.codehaus.mojo.gwt.test.client.Hello:

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.codehaus.mojo.gwt.test.Hello/Hello"/>
  <set-property name="user.agent" value="gecko1_8"/>
</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.org/maven-v4_0_0.xsd">
  <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>
    <dependency>
      <groupId>com.google.gwt</groupId>
      <artifactId>gwt-servlet</artifactId>
      <scope>runtime</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>
          <draftCompile>true</draftCompile>
          <optimizationLevel>1</optimizationLevel>          
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-war-plugin</artifactId>
        <version>2.1</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.

Main Project: reactor

Eventually, we will glue it all together in the main project's POM:

<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>org.codehaus.mojo.gwt.it</groupId>
  <artifactId>reactor</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>pom</packaging>

  <build>
    <pluginManagement>
      <plugins>
        <plugin>
          <groupId>org.codehaus.mojo</groupId>
          <artifactId>gwt-maven-plugin</artifactId>
          <version>@pom.version@</version>
        </plugin>
        <plugin>
          <artifactId>maven-war-plugin</artifactId>
          <version>2.1</version>
        </plugin>
      </plugins>
    </pluginManagement>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>2.1</version>
        <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>@gwt.version@</version>
        <scope>provided</scope>
      </dependency>
      <dependency>
        <groupId>com.google.gwt</groupId>
        <artifactId>gwt-servlet</artifactId>
        <version>@gwt.version@</version>
        <scope>runtime</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <modules>
    <module>jar</module>
    <module>war</module>
  </modules>
</project>

Note the two subprojects are declared as modules here.

Compiling the Application

In order to compile the whole project Maven can be invoked like this:

reactor$ mvn clean package

Since GWT-maven-plugin's compile-goal is bound to Maven's process-classes lifecycle phase, the GWT compiler will compile all client code into JavaScript. This code will be packaged along with any other resources into the resulting WAR bundle.

You'll find the packaged application in war/target/war-1.0-SNAPSHOT.war