2010/02/06

Efficient GWT development with Eclipse-Maven integration

In this article I present an efficient GWT development environment based on Eclipse and Maven, with tight integration between them.

Goals
  • Maven-friendly Eclipse project
  • easy development using Eclipse and WTP
  • ability to build the entire project using Maven (eg. for deployment or nightly builds)
It should be noted that there are many ways for efficient integration of the given technologies, I present here only one of them.
If you want to skip the 'boring' step-by-step explanation, simply check out the project from SVN :)



Requirements

The followings should be installed and configured properly:
Create and configure a Dynamic Web project
    Let's start with a slightly customized WTP Dynamic Web Project, by changing the default project layout to a more Maven-friendly one:

    • create a new Dynamic Web Project



    • change the source folder to src/main/java and the output folder to target/classes



    • change the content directory to src/main/webapp



    It is a good practise to set the project encoding explicitly, so open the project properties dialog and set it to UTF-8:


    Setup Maven support

    Create a pom.xml file with a basic content:

    <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>
    
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        </properties>
    
        <groupId>com.jvminside.blog</groupId>
        <artifactId>gwt-eclipse-maven-webapp</artifactId>
        <version>1.0.0-SNAPSHOT</version>
        <packaging>war</packaging>
    
        <build>
            <finalName>gwtapp</finalName>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-resources-plugin</artifactId>
                    <version>2.4.1</version>
                    <configuration>
                        <encoding>UTF-8</encoding>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>2.1</version>
                    <configuration>
                        <source>1.6</source>
                        <target>1.6</target>
                        <encoding>UTF-8</encoding>
                    </configuration>
                </plugin>
            </plugins>
        </build>
        
    </project>
    

    Enable Maven Dependency Management in the context menu of the project:


    From now on M2Eclipse manages our Maven dependencies by maintaning a dynamic Eclipse library dependency based on the pom.xml file:


    Add the GWT dependencies

    Add the gwtVersion property to the properties section of the pom.xml:

    <properties>
        ...
        <gwtVersion>2.0.0</gwtVersion>
    </properties> 

    Add the GWT user and dev library dependencies:

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

    (Starting with GWT 2.0 the dev library is platform-independent. Older GWT versions had platform-specific dev library, so it required much more configuration to setup a portable build.)

    The newly added dependencies are automatically added to the build path:


    Now we can implement our application - which simply displays a message alert :). See the source code of the GWT module XML, the application class and the HTML host file in the SVN repository.

    GWT-Maven integration

    During GWT compilation the Java source files of the client-side code must be available on the classpath for the GWT compiler. The easiest solution is to mark the entire src/main/java folder as a resource folder, so Maven will copy all Java files to the target/classes directory during the process-resources lifecycle phase:

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

    So, the Java source files are copied during a Maven build, but what about Eclipse builds? Fortunatelly M2Eclipse handles this as well because it executes process-resources on resource changes. This is configured in the project settings:


    We use the maven-gwt-plugin to do the rest of the GWT integration:

    <build> 
        ...
        <plugins>
            ...
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>gwt-maven-plugin</artifactId>
                <version>1.2</version>
                <configuration>
                    <module>com.jvminside.blog.gwtapp.GwtApp</module>
                    <enableAssertions>true</enableAssertions>
                    <gwtVersion>${gwtVersion}</gwtVersion>
                    <runTarget>/gwtapp/index.html</runTarget>
                    <noServer>true</noServer>
                    <port>40000</port>
                    <debugPort>9008</debugPort>
                    <inplace>true</inplace>
                    <extra>${project.build.directory}/gwt-extra</extra>
                    <gen>${project.build.directory}/gwt-gen</gen>
                    <extraJvmArgs>-Xmx256m -Xss16m</extraJvmArgs>
                    <webappDirectory>${project.build.directory}/${project.build.finalName}</webappDirectory>
                    <warSourceDirectory>${project.build.directory}/${project.build.finalName}</warSourceDirectory>
                </configuration>
                <executions>
                    <execution>
                        <id>gwt-compile</id>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                        <phase>process-classes</phase>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    

    The key settings are:
    • noServer is set to true because we will use a standalone Tomcat to run the web application (instead of GWT's built-in servlet container)
    • the GWT files are compiled to target/gwtapp (gwtapp is the finalName of the project)
    • GWT compilation is performed in the process-classes phase

    We can now compile the GWT application by executing mvn process-classes. We must do this at least once to generate the hosted.html file which is necessary to run the application in devmode.

    GWT-WTP integration

    If we deploy and run the application at this point, it won't work because the resources of the web application are at two separate locations:
    • static resources in src/main/webapp
    • generated GWT resources in target/gwtapp/gwt
    The project's content directory was set to src/main/webapp when we created the project, so the other folder is unknown to the servlet container. Fortunatelly WTP can easily handle any number of content directories, and merge them to a single context path when publishing the web application.
    The related settings are stored in the .settings/org.eclipse.wst.common.component file, let's add our other content directory to it:

    <?xml version="1.0" encoding="UTF-8"?>
    <project-modules id="moduleCoreId" project-version="1.5.0">
        <wb-module deploy-name="jvminside-gwt-eclipse-maven-integration">
            <wb-resource deploy-path="/" source-path="/src/main/webapp"/>
            <wb-resource deploy-path="/" source-path="/target/gwtapp"/>
            <wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/java"/>
            <property name="context-root" value="gwtapp"/>
            <property name="java-output-path"/>
        </wb-module>
    </project-modules>
    

    If we deploy the application now, it works as expected!

     

    Eclipse launch configurations for DevMode

    After the project is built with mvn process-classes, it is very easy to run it in devmode from the command line, simply execute mvn gwt:run.
    Debugging is almost as easy, execute mvn gwt:debug, then connect to the process with Eclipse's remote debugging option.
    There are 3 launch configurations in the project which do just these:




    Building a WAR file

    Execute mvn package, that's it.

    Future features

    Nothing is perfect for everything, this project could be enhanced further - depending on your needs, for example:
    Resources

      5 comments:

      1. You could also use the gwt archetype from the codehaus mojo plugin for maven. Quite a bit easier IMHO

        ReplyDelete
      2. I agree, this post may be more useful if someone wants to understand the steps to create the integration.

        ReplyDelete
      3. This information you provided in the blog that was really unique I love it!!, Thanks for sharing such a great blog..Keep posting..


        JAVA Training in Chennai

        ReplyDelete
      4. These are some of the common web application development solutions we provide Web 2.0, Community and Networking Applications Effective and easy-to-use user

        Web Application Development

        ReplyDelete