Modularizing GWT Applications with GWT-Maven
Last week, I spent some time modularizing the GWT application I'm working on. By modularizing, I mean splitting the code from one GWT module into a "core" and "webapp" module. The reason for doing this was so the "core" module could be used by another GWT application. Creating GWT Modules is fairly straightforward, but it wasn't as intuitive as expected when using the gwt-maven-plugin.
The hardest part of moving the code was figuring out how to run tests in the new "core" module. After getting it all working, it seems easy enough. Hopefully this post will make it easy for others. Here's the steps I'd recommend:
- Convert your GWT project into a multi-module project where you have a top-level pom.xml and two sub-modules (e.g. gwt-core and gwt-webapp).
- Do the normal single-to-multi-project Maven stuff like declaring the <parent> element in the modules and moving plugins/dependencies to the top-level pom.xml.
- Refactor your gwt-webapp project to push down all shared classes (and their tests) to gwt-core.
- In the gwt-core project, include *.xml and *.java in your JAR so GWT can extract/compile the source code when building gwt-webapp.
<resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.java</include> <include>**/*.xml</include> </includes> </resource> </resources>
- In
gwt-core/src/main/java
, create aCore.gwt.xml
that references the modules you'd like to use in all your applications. For example:<module> <inherits name="com.google.gwt.user.User"/> <inherits name="com.google.gwt.i18n.I18N"/> <inherits name="com.extjs.gxt.ui.GXT"/> <inherits name="pl.rmalinowski.gwt2swf.GWT2SWF"/> </module>
- Now the tricky part begins, mostly because of how the gwt-maven plugin currently works. In
src/test/java
, create aNoOpEntryPoint.gwt.xml
that inherits your Core module and defines an EntryPoint.<module> <inherits name="com.company.app.Core"/> <entry-point class="com.company.app.NoOpEntryPoint"/> </module>
- Create a
NoOpEntryPoint.java
class in the same directory asNoOpEntryPoint.gwt.xml
.public class NoOpEntryPoint implements EntryPoint { public void onModuleLoad() { // do nothing } }
- In any class that extends GWTTestCase (I usually create a parent class for all tests), reference the NoOpEntryPoint in the
getModuleName()
method.@Override public String getModuleName() { return "com.company.app.NoOpEntryPoint"; }
- Lastly, in the gwt-maven plugin's configuration (in gwt-core/pom.xml), reference the NoOpEntryPoint in <compileTargets>, a non-existent file in <runTarget> and only the "test" goal in the executions.
<plugin> <groupId>com.totsp.gwt</groupId> <artifactId>maven-googlewebtoolkit2-plugin</artifactId> <version>2.0-beta26</version> <configuration> <compileTargets> <value>com.company.app.NoOpEntryPoint</value> </compileTargets> <runTarget>com.company.app.NoOpEntryPoint/doesntexist.html</runTarget> <logLevel>INFO</logLevel> <style>OBF</style> <noServer>false</noServer> <extraJvmArgs>-Xmx512m</extraJvmArgs> <gwtVersion>${gwtVersion}</gwtVersion> <testFilter>*GwtTestSuite.java</testFilter> <testSkip>${skipTests}</testSkip> </configuration> <executions> <execution> <goals> <goal>test</goal> </goals> </execution> </executions> </plugin>
The results of modularizing your application are beneficial (shared code) and detrimental (you have to mvn install
gwt-core whenever you make changes in shared classes). If you know of a way to configure the gwt-maven plugin to read sources from both gwt-core and gwt-webapp in hosted mode, I'd love to hear about it.
For your info, the gwt-maven plugin is now hosted at codehaus as part of mojo project. It's groupId is now org.codehaus.mojo, but features are still the same you used in this article
http://mojo.codehaus.org/gwt-maven-plugin/
Posted by nicolas.deloof on March 23, 2009 at 06:08 PM MDT #
Posted by Matt Raible on March 23, 2009 at 06:12 PM MDT #
Nicolas, we are still supporting the Google Code GWT-Maven plugin until I get a chance to get in and validate things. We aren't adding new features to GWT-Maven, but we are keeping it alive for those that use it, until a clean switch can take place. (I should be off of several other side projects within a few weeks, and then I will be in the mix there more - THEN once I am familiar with it all, I will freeze the GWT-Maven one and point people at Codehaus.
For now though, GWT-Maven is still what I would recommend. That recommendation though isn't a reflection that one is better than the other, it's just that I haven't used the Codehaus plugin yet, so I can't vouch for it - and again we are sill supporting GWT-Maven.
Matt, long story, I agreed to merge with Codehaus several months back but also told the GWT-Maven community that everything will remain the same until I can sign off on the Codehaus stuff. I want the transition for users to be seamless. (This was all discussed some time back on the GWT-Maven group, like I said, long story.) Eventually there will be only one, and it will be the Codehaus one, but we aren't there yet. And, if I do things correctly, as planned, all users won't have to change approaches/poms/etc.
And BTW, great article. Thanks.
Posted by Charlie Collins on March 24, 2009 at 01:07 AM MDT #
Posted by Cyril Lakech on March 24, 2009 at 08:57 AM MDT #
Posted by Gabriel on March 26, 2009 at 03:46 PM MDT #
I don't think you have to inherit the GWT modules in your own module if you inherit from GXT since GXT already inherits those itself.
Thanks for all the great articles!
Posted by Peter Leibiger on March 27, 2009 at 10:35 AM MDT #
Hi Matt,
Thanks for your post! Very useful as usual. Could you shed some light on what does "gwt-core" and "gwt-webapp" contains in your case? Do you use any MVC framework such as struts or spring in addition to GWT?
How different is your modular separation when compared to this:
http://gwt-maven.googlecode.com/svn/trunk/maven-googlewebtoolkit2-sample/
Thank you and looking forward to learning from you!
Posted by Oscar Perez on April 03, 2009 at 12:25 PM MDT #
My manager is a modularization freak. I prefer to have 1-project-with-1-module. The 1-project-with-1-module makes sure that I have super-high speed. A jetty:run with auto-redeploy or return-key-to-redeploy works better than mvn install on half a dozen modules and then running the jetty app.
I understand that things get different with GWT, but I still find multi module a bigger pain than single module projects.
Posted by Rahul Somasunderam on June 29, 2009 at 02:16 AM MDT #
Winner again Matt .
What's your opinion about MVP .
Nearly a decade ago we were happy to write spaghetti code in C++ (or at least I was at uni) then we were hit with MVC and life changed for better .
Now GWT has come up with MVP . I am missing the "C" . I feel applications have very tight coupling with the view if we do not have a controller .
And thoughts or blog on this .
Cheers
Posted by Shahzeb on April 29, 2010 at 05:16 AM MDT #
Posted by anon on January 04, 2011 at 11:55 PM MST #
Thanks for this post, helped me out a good bit.
A little tweaking I did though, since I did not want my sources wrapped up with the war file...
in the shared module (core):
And then add that as a provided dependency in the app. Thanks for the post.
Posted by Justin Smith on June 24, 2011 at 11:55 AM MDT #