About

GWT Tip: working with maven multi-modules projects

Many question have been asked recently in the GWT Users Group about how to work with GWT maven projects that contain multiple GWT modules, and how to properly set up the dev mode. This post aims to provide an example of a maven configuration for a project with multiple modules. There is off course no one right way to do this, and the configuration may differ from one project to another.

Before getting started, it’s worth taking a look at the existing maven plugins in GWT ecosystem. There are two GWT maven plugins:

  • org.codehaus.mojo: This plugin is considered as the legacy plugin. it is tied to a GWT version, because it brings the gwt-dev and gwt-servlet to the classpath ( so no need to include them). The advantage of this plugin is the configuration of gwt compiler options provided as maven properties.
  • net.ltgt.gwt.maven: This plugin is considered as the new generation maven project. it’s not tied to a sepecific GWT version, so you have to bring in gwt-dev, and gwt-servlet. This plugin provides two different packaging (gwt-lib, gwt-app), and provides freedom on the arguments provided to the gwt compiler.

For a more detailed comparison between the two plugins, you can refer to Thomas Broyer‘s answer on stackoverflow.

Although both of them could be used, net.ltgt.gwt.maven is likely to be more suited for projects with multiple modules because it’s designed to support reactor builds. If org.codehaus.mojo is to be used, the user need to explicitely run mvn install.

A GWT app with Java EE backend

To provide an example, let’s suppose that we have an application with two GWT modules for the client side (module1, module2), and a server module that uses Java EE servlets to handle server requests. Our parent pom.xml looks something like:

<dependencies>
		<dependency>
			<groupId>com.google.gwt</groupId>
			<artifactId>gwt-user</artifactId>
			<version>${gwtVersion}</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>com.google.gwt</groupId>
			<artifactId>gwt-dev</artifactId>
			<version>${gwtVersion}</version>
			<scope>provided</scope>
		</dependency>
	</dependencies>
	<modules>
		<module>client-module1</module>
		<module>client-module2</module>
		<module>server</module>
  </modules>

In our server module, we have two servlets that manage the context for /module1 and /module2.

Module1Servlet.java

@WebServlet("/module1")
public class Module1Servlet extends HttpServlet {
	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		req.getRequestDispatcher("/module1.jsp").forward(req, resp);
	}

}

Module2Servlet.java

@WebServlet("/module2")
public class Module2Servlet extends HttpServlet {
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		 req.getRequestDispatcher("/module2.jsp").forward(req, resp);
	}

}

Our 2 GWT modules display a simple Label widget.

We are going to configure our GWT client modules to output the result of the Java to Javascript compilation directly into the server module. Here is a snippet of the pom.xml:

  	<build>
		<resources>
			<resource>
				<directory>src/main/java</directory>
			</resource>
		</resources>

		<outputDirectory>${project.build.directory}/${project.build.finalName}/WEB-INF/classes</outputDirectory>


		<plugins>
			<plugin>
				<groupId>net.ltgt.gwt.maven</groupId>
				<artifactId>gwt-maven-plugin</artifactId>
				<version>1.0-rc-6</version>
				<extensions>true</extensions>
				<configuration>
					<classpathScope>compile</classpathScope>
					<moduleName>com.gwidgets.Module1</moduleName>
					<moduleShortName>module1</moduleShortName>
 				    <warDir>${basedir}/../server/target/server-${project.version}</warDir>
					<devmodeWorkDir>${basedir}/../server/target/server-${project.version}</devmodeWorkDir>
					<webappDirectory>${basedir}/../server/target/server-${project.version}</webappDirectory> 
					<devmodeArgs>
						<arg>-noserver</arg>
						<arg>-codeServerPort</arg>
						<arg>4522</arg>
					</devmodeArgs>
				</configuration>
			</plugin>
		</plugins>
	</build>

Explanation :

In this configuration, we provided the -noserver argument which tells GWT not to run its own dev server(jetty). We also provided a custom port because we want to run the dev mode for the two modules at the same time, so we would want to avoid running both modules on default port.
We also provided the devmodeWorkDir property, which tells the GWT compiler where to output the compiled javascript files. The reason for choosing the project build directory (refered to by the ${project.build.directory} property) for the server module is that once the server is run, it uses the /target (or the build directory) as a source directory, so any changes that, for example, are introduced in our modules during the dev mode need to be reflected in the source directory of the running server.
We also provided the webappDirectory which is used by the dev mode as a war directory. It is usually the same as devmodeWorkDir.
Finally, the warDir tells GWT compiler where to write the deployable file. This option will be helpful when packaging the application for deploying.

Running the dev mode:

First of all, we need to compile our GWT modules and run the dev mode. We need to run the following goals on both modules:

 mvn gwt:generate-module compile gwt:devmode 

To run the dev mode, we have to first launch the server module. Any server can be used for this purpose. In this example, we used jetty plugin for maven. Here is a snippet for the configuration:

         <plugin>
			<groupId>org.eclipse.jetty</groupId>
			<artifactId>jetty-maven-plugin</artifactId>
			<version>9.2.0.M0</version>
			<configuration>
			<webAppSourceDirectory>${project.build.directory}/${project.build.finalName}</webAppSourceDirectory>
			</configuration>
		</plugin> 

Now we can run our server using :

 mvn package jetty:run 

Result: we can run dev mode for both modules at the same time, and debug both at the same time.
devmode-md1-md2

loaded-md1-md2

Packaging the app

For packaging our modules as a depolyable war file, we need to first run

 mvn gwt:compile

on both our GWT modules and run

 mvn package 

on our server module.

Take away

This example illustrates the flexibilty of net.ltgt.gwt.maven plugin in working with multiple GWT modules. Configurations may differ from a project to another, but the concept remains the same: directing the GWT compiler output and source directory to where want to run our server. For further examples, you can check out this tutorial by Brandon Donnelson on how to use dev mode with Tomcat Plugin in Eclipse IDE.

Full example code: https://github.com/zak905/gwt-multimodule-example

For enquiries contact Francesca Tosi

Archive

Subscribe

Atom

Blog Partners