Saturday, January 8, 2011

Spring and GWT Integration using Maven and GWTHandler (Part 1)

In this tutorial we will setup a simple GWT application and integrate it with Spring. We will use GWTHandler to map GWT's RPC services to Spring beans, and utilize Maven to manage and build our project. Our application is the typical GWT Hello application we see when we create a new GWT project.

Note: An updated version of this guide is available at Spring 3.1: GWT Maven Plugin and GWTHandler Integration

What is GWTHandler?
The GWTHandler allows you to quickly map multiple RPC service beans to different URLs very similar to the way Spring's SimpleUrlHandlerMapping maps URLs to controllers. The
mapped beans are internally wrapped into GWTRPCServiceExporter
instances

Source: http://gwt-widget.sourceforge.net/?q=node/54
What is GWT?
Google Web Toolkit (GWT) is a development toolkit for building and optimizing complex browser-based applications. GWT is used by many products at Google, including Google AdWords and Orkut. It's open source, completely free, and used by thousands of developers around the world.

Source: http://code.google.com/webtoolkit/
What is Spring?
[T]he leading platform to build and run enterprise Java applications. Led and sustained by SpringSource, Spring delivers significant benefits for many projects, increasing development productivity and runtime performance while improving test coverage and application quality.

Source: http://www.springsource.org/
What is Maven?
Apache Maven is a software project management and comprehension tool. Based on the concept of a project object model (POM), Maven can manage a project's build, reporting and documentation from a central piece of information.

Source: http://maven.apache.org/
Here's what we will be building:

Initial run: plain GWT

Final run: GWT and Spring

Now that you've seen what we'll be building, let's create our project.

I assume you're running Eclipse with m2eclipse installed (or Spring's STS). If you don't have any of these, please visit the following links:
- Eclipse: http://www.eclipse.org/downloads/
- m2eclipse: http://m2eclipse.sonatype.org/
or
- STS: http://www.springsource.com/products/springsource-download-center

1. Open your IDE. Create a New Project

2. Select Maven. Then select Maven Project.

3. On the Select an Archetype screen, choose gwt-maven-plugin. Make sure the version is 2.1.0-1 or greater! If not, update your catalog.

4. Click Next. On the Specify Archetype parameters window, enter an appropriate Artifact Id and Package. Then make sure you add a value on the module parameter. If you're new to GWT, just follow the values from the screenshot below:

5. Click Finish when you're done. You should see the following project structure:

Notice there are multiple red markers. These mean something is wrong with our project. Upon checking all files, we realize the Async interfaces needs to be created first!

To resolve this, we can manually create the Async interfaces. However, Maven has a goal support to automatically generate the Async interfaces. For more info, please visit http://mojo.codehaus.org/gwt-maven-plugin/examples/asyn.html

We will be using the generateAsync goal to generate the interfaces.

6. Right-click on your project. Select Run As. Then Select Run Configurations

7. Find the Maven Build section on the Run Configurations window

8. Press the New button to create a new Maven Build configuration.

9. Enter the following details for this new configuration:
Name: generateAsync
Base directory: (click on Browse and find your project)
Goals: gwt:generateAsync

10. Click Apply. Click Run. You should see the following output on the Console window:
[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building GWT Maven Archetype 1.0.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- gwt-maven-plugin:2.1.0-1:generateAsync (default-cli) @ spring-gwt-integration ---
[WARNING] Encoding is not set, your build will be platform dependent
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.316s
[INFO] Finished at: Fri Jan 07 23:49:31 2011
[INFO] Final Memory: 6M/124M
[INFO] ------------------------------------------------------------------------
The Async interfaces are generated automatically. But where are they saved?

11. Go your project directory. Open the target folder, and you will see the generated-sources folder. This is where Maven saved the Async interfaces. Expand the sub-folders until you find the Async interfaces: GreetingServiceAsync.java and Messages.java

12. Copy these files and paste them on the client package. In my case, it's org.krams.tutorial.client

Notice most of the red warnings are now gone, but there's still one left. That's because Eclipse is complaining that we have set the wrong output directory, but in fact, we didn't. You can safely ignore this warning.

Now let's run our project and see how it would look like. We will be using Maven again to run the application. We cannot use the usual Run As >> Web Application command here because we're using Maven.

To run the application, we'll use the gwt:run goal.

13. To create the Maven gwt:run goal, follow the same exact steps when we created the generateAsync goal. But of course, you will need to change the details to the following:
Name: gwt-run
Base directory: (click on Browse and find your project)
Goals: gwt:run

14. Click Apply. Click Run. The GWT Development Mode window will appear.

15. Click on Launch Default Browser to run the application. Or you may copy the link and paste it in your browser.

You should see the following application:

Play with the application. Close it when you're done. What we saw here is the GWT application.

Our next task is to integrate this application with Spring. Visit the following link for the continuation: Spring and GWT Integration using Maven and GWTHandler (Part 2)
StumpleUpon DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google I'm reading: Spring and GWT Integration using Maven and GWTHandler (Part 1) ~ Twitter FaceBook

Subscribe by reader Subscribe by email Share

15 comments:

  1. Your screen shots are all missing.. makes it hard to follow

    ReplyDelete
  2. Hello krams::
    Thank you for your great tutorial, but I have small trouble.

    I'm using STS v2.5.2 and got the following error at step 13: Invalid task 'gwt-run': you must specify a valid lifecycle phase, or a goal in the format plugin:goal or pluginGroupId:pluginArtifactId:pluginVersion:goal

    But I could make the project runs by using maven command-line: mvn gwt:run

    What do I miss any configuration of the project in STS?

    ReplyDelete
  3. @phucN, that is tricky. Did you create a new project or you're running the sample one from this tutorial? I would guess it's a Maven dependency issue with Eclipse.

    ReplyDelete
  4. This would have been so good to me if it worked. it is just what i am looking for but i am getting all kind of errors here...
    i couldn't get over the first step even here is the error
    [INFO] Scanning for projects...
    [INFO]
    [INFO] ------------------------------------------------------------------------
    [INFO] Building GWT Maven Archetype 1.0.0-SNAPSHOT
    [INFO] ------------------------------------------------------------------------
    [INFO]
    [INFO] --- gwt-maven-plugin:2.1.0-1:generateAsync (default-cli) @ myapp---
    [WARNING] Encoding is not set, your build will be platform dependent
    [ERROR] Failed to generate Async interface
    java.lang.NullPointerException
    at com.thoughtworks.qdox.model.JavaMethod.getReturnType(JavaMethod.java:464)
    at com.thoughtworks.qdox.model.JavaMethodDelegate.getReturnType(JavaMethodDelegate.java:26)
    at com.thoughtworks.qdox.model.JavaMethodDelegate.getReturnType(JavaMethodDelegate.java:166)
    at org.codehaus.mojo.gwt.GenerateAsyncMojo.generateAsync(GenerateAsyncMojo.java:274)
    at org.codehaus.mojo.gwt.GenerateAsyncMojo.scanAndGenerateAsync(GenerateAsyncMojo.java:191)
    at org.codehaus.mojo.gwt.GenerateAsyncMojo.execute(GenerateAsyncMojo.java:138)
    at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:107)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:209)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:84)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:59)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.singleThreadedBuild(LifecycleStarter.java:183)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:161)
    at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:319)
    at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:156)
    at org.apache.maven.cli.MavenCli.execute(MavenCli.java:534)
    at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:196)
    at org.apache.maven.cli.MavenCli.main(MavenCli.java:141)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:290)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:230)
    at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:409)
    at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:352)
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD FAILURE
    [INFO] ------------------------------------------------------------------------
    [INFO] Total time: 1.994s
    [INFO] Finished at: Mon Jan 30 22:58:31 IST 2012
    [INFO] Final Memory: 10M/213M
    [INFO] ------------------------------------------------------------------------
    [ERROR] Failed to execute goal org.codehaus.mojo:gwt-maven-plugin:2.1.0-1:generateAsync (default-cli) on project myapp: Failed to generate Async interface: NullPointerException -> [Help 1]
    [ERROR]
    [ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
    [ERROR] Re-run Maven using the -X switch to enable full debug logging.
    [ERROR]
    [ERROR] For more information about the errors and possible solutions, please read the following articles:
    [ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException

    ReplyDelete
  5. @Anonymous, I will try to update this guide to the latest Spring (3.1.0) and GWT versions (2.4.0). My old workspace/Eclipse that had this setup had been long gone. I'm using a different version so I can't recreate the issue. Currently, I'm testing 2.4.0 without the GWT IDE plugin. I apologize if right now I can't provide you a solution.

    I will also change the source code repo to Github instead of Google Code's

    ReplyDelete
  6. @Anonymous, I've just tried the latest gwt-maven-plugin 2.4.0 using a fresh Eclipse installation. I'm able to follow the steps in this tutorial, with an extra addition for the internationalization. Here's what I did.

    1. Open Eclipse
    2. Create a Maven project using gwt-maven-plugin 2.4.0
    3. Create a new run configuration with the following goals: gwt:generateAsync
    4. Run that configuration. Copy the generated GreetingServiceAsync.java under the target folder to the client folder
    5. Create a new run configuration with the following goals: gwt:i18n
    6. Run that configuration. Copy the generated Message.java under the target folder to the client folder
    7. Create a new run configuration with the following goals: gwt:run
    8. Wait for the application to run and wait for the Gwt Development Mode window to appear.
    9. Open a browser and visit http://127.0.0.1:8888/gwtmodule.html?gwt.codesvr=127.0.0.1:9997

    ReplyDelete
  7. first of all i thought i wont post as Anonymous anymore and

    Thanks, this runs. but i have the most importent issues now:

    I am unable to debug the application! i have tried to do mvn:debug goal (not even sure that is ok) but that gives me an error that the address is already in use??

    [INFO] FATAL ERROR in native method: JDWP No transports initialized, jvmtiError=AGENT_ERROR_TRANSPORT_INIT(197)
    [ERROR] ERROR: transport error 202: bind failed: Address already in use
    [ERROR] ERROR: JDWP Transport dt_socket failed to initialize, TRANSPORT_INIT(510)

    So how am i supposed to debug the application?.

    ReplyDelete
  8. @Wolfstein, have you checked the gwt:debug goal? See http://mojo.codehaus.org/gwt-maven-plugin/debug-mojo.html (I assume you're using gwt-maven-plugin 2.4.0.)

    And maybe you already know this, Google also has debugging suggestions: http://code.google.com/webtoolkit/doc/latest/DevGuideCompilingAndDebugging.html

    ReplyDelete
  9. @Wolfstein, you might want to check Testing GWT code with Maven at http://mojo.codehaus.org/gwt-maven-plugin/user-guide/testing.html

    ReplyDelete
  10. i am actually having
    org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.codehaus.mojo:gwt-maven-plugin:2.4.0:debug (default-cli) on project spring-gwt-integration: Command [[

    when i try to debug.

    ReplyDelete
  11. I have uploaded an updated guide that uses the latest Spring 3.1, gwt-sl 1.3-RC1, and GWT Maven Plugin 2.4.0.

    See http://krams915.blogspot.com/2012/02/spring-31-gwt-maven-plugin-and_3309.html

    ReplyDelete
  12. I have read your blog its very attractive and impressive. I like it your blog.

    Spring online training Spring online training Spring Hibernate online training Spring Hibernate online training Java online training

    spring training in chennai spring hibernate training in chennai

    ReplyDelete
  13. Good Post! Thank you so much for sharing this pretty post, it was so good to read and useful to improve my knowledge as updated one, keep blogging.

    core java training in Electronic City

    Hibernate Training in electronic city

    spring training in electronic city

    java j2ee training in electronic city

    ReplyDelete
  14. Happy to found this blog. Good Post!. It was so good to read and useful to improve my knowledge as updated one, keep blogging. Hibernate Training in Electronic City
    Java Training in Electronic City

    ReplyDelete