Saturday, January 8, 2011

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

In this tutorial we will continue what we had left off from Spring and GWT Integration using Maven and GWTHandler (Part 1). Last time we set-up a simple GWT project using Maven. We generated the Async interfaces and run the application using specialized Maven goals. Now we will start integrating Spring with our current GWT application.

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

We start by declaring the necessary XML configurations. We will do a side-by-side (actually top-by-down) comparison of the old and new configurations. Let's begin with the web.xml.

web.xml (old)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>

  <!-- Servlets -->
  <servlet>
    <servlet-name>greetServlet</servlet-name>
    <servlet-class>org.krams.tutorial.server.GreetingServiceImpl</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>greetServlet</servlet-name>
    <url-pattern>/gwtmodule/greet</url-pattern>
  </servlet-mapping>

  <!-- Default page to serve -->
  <welcome-file-list>
    <welcome-file>gwtmodule.html</welcome-file>
  </welcome-file-list>

</web-app>
web.xml (new)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>

  <listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener>

 <!-- Front Controller for all GWT Spring based servlets -->
 <servlet>
  <servlet-name>gwt</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
 </servlet>
 
 <!-- Front Controller for all Spring based servlets -->
 <servlet>
  <servlet-name>spring</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
 </servlet>
 
 <!-- Don't forget to declare a gwt-servlet.xml -->
 <servlet-mapping>
  <servlet-name>gwt</servlet-name>
  <url-pattern>gwtmodule/rpc/*</url-pattern>
 </servlet-mapping>
 
 <!-- Don't forget to declare a spring-servlet.xml -->
 <servlet-mapping>
  <servlet-name>spring</servlet-name>
  <url-pattern>krams/*</url-pattern>
 </servlet-mapping>

</web-app>
We've declared two servlets:
gwt-servlet - for displaying GWT 
spring-servlet - for displaying JSPs
We actually just need the gwt-servlet, but we set-up the spring-servlet here to demonstrate that we can combine JSPs and GWT in the same application

Here's gwt-servlet.xml

gwt-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans 
            http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
 
 <!-- 
  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, with the notable difference that you cannot specify a service interface in the configuration
  and the service beans must implement the RemoteService interface (as a matter of fact there is
  a workaround even for that by providing your own implementation of a RPCServiceExporter -
  interested readers please consult the javadocs for GWTHandler).
  
  See 3.2 Publishing multiple beans - GWTHandler 
  http://gwt-widget.sourceforge.net/?q=node/54 -->
 
 <!--  If you wanna research further about annotation support with GWT Handler.
   See http://groups.google.com/group/gwt-sl/browse_thread/thread/f563b200aa0af307# -->
   
 <!-- Or create our own implementation: 
     Seehttp://groups.google.com/group/gwt-sl/msg/3677e59c4a7c2dee -->
   
  <!-- A GWT Spring bean -->   
 <bean id ="greetingService" class="org.krams.tutorial.server.GreetingServiceImpl" >
  <property name="springService" ref="springService" />
 </bean>
 
 <!-- A Spring bean-->
 <bean id="springService" class="org.krams.tutorial.service.SpringService" />
 
 <!-- The GWT handler. Watch out the mappings! -->
 <bean class="org.gwtwidgets.server.spring.GWTHandler">
  <property name="mappings">
   <map>
    <entry key="/greet" value-ref="greetingService"/></map>
  </property>
 </bean>
 
</beans>
Here we declared a GWTHandler. This is basically similar to SimpleUrlHandlerMapping where a URL is mapped to a particular bean. In order for GWTHandler to match the mapping request, we need to modify the GreetingService interface (I'll show you the old implementation and the new one)

GreetingService (old)
package org.krams.tutorial.client;

import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;

/**
 * The client side stub for the RPC service.
 */
@RemoteServiceRelativePath("greet")
public interface GreetingService extends RemoteService {
  String greetServer(String name) throws IllegalArgumentException;
}

GreetingService (new)
package org.krams.tutorial.client;

import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;

/**
 * The client side stub for the RPC service.
 */
@RemoteServiceRelativePath("rpc/greet")
public interface GreetingService extends RemoteService {
  String greetServer(String name) throws IllegalArgumentException;
}
We've changed the path from greet to rpc/greet. Remember in the web.xml we've declared a url pattern:
<!-- Don't forget to declare a gwt-servlet.xml -->
 <servlet-mapping>
  <servlet-name>gwt</servlet-name>
  <url-pattern>gwtmodule/rpc/*</url-pattern>
 </servlet-mapping>
Make sure you correctly map your paths! Let me summarize that for you:
web.xml declaration: gwtmodule/rpc/*
interface declaration: rpc/greet
gwt-servlet.xml declaration: /greet

For a thorough discussion of GWTHandler, see 3.2 Publishing multiple beans - GWTHandler at http://gwt-widget.sourceforge.net/?q=node/54

In this configuration we mapped the /greet URL to the greetingService bean.
<entry key="/greet" value-ref="greetingService"/></map>
This greetingService bean is actually the default service implementation that was provided to us when we created the application. It references GreetingServiceImpl. We need to modify this class!

Let me show you first the original implementation (the one that's auto-generated for us):

GreetingServiceImpl (auto-generated)
package org.krams.tutorial.server;

import org.krams.tutorial.client.GreetingService;
import org.krams.tutorial.shared.FieldVerifier;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;

/**
 * The server side implementation of the RPC service.
 */
@SuppressWarnings("serial")
public class GreetingServiceImpl extends RemoteServiceServlet implements
    GreetingService {

  public String greetServer(String input) throws IllegalArgumentException {
    // Verify that the input is valid.
    if (!FieldVerifier.isValidName(input)) {
      // If the input is not valid, throw an IllegalArgumentException back to
      // the client.
      throw new IllegalArgumentException(
          "Name must be at least 4 characters long");
    }

    String serverInfo = getServletContext().getServerInfo();
    String userAgent = getThreadLocalRequest().getHeader("User-Agent");

    // Escape data from the client to avoid cross-site script vulnerabilities.
    input = escapeHtml(input);
    userAgent = escapeHtml(userAgent);

    return "Hello, " + input + "!<br><br>I am running " + serverInfo
        + ".<br><br>It looks like you are using:<br>" + userAgent;
  }

  /**
   * Escape an html string. Escaping data received from the client helps to
   * prevent cross-site script vulnerabilities.
   *
   * @param html the html string to escape
   * @return the escaped string
   */
  private String escapeHtml(String html) {
    if (html == null) {
      return null;
    }
    return html.replaceAll("&", "&").replaceAll("<", "<").replaceAll(
        ">", ">");
  }
}
We need to remove the following in order for GWTHandler to recognize this class
extends RemoteServiceServlet
After you remove this reference, some parts of the code will get flagged. Just delete those, and replace it with this new implementation:

GreetingServiceImpl (new)
package org.krams.tutorial.server;

import org.krams.tutorial.client.GreetingService;
import org.krams.tutorial.service.SpringService;
import org.krams.tutorial.shared.FieldVerifier;

/**
 * The server side implementation of the RPC service.
 */
@SuppressWarnings("serial")
public class GreetingServiceImpl implements
    GreetingService {
  
  // Our custom Spring Service bean
  private SpringService springService;
  
  public String greetServer(String input) throws IllegalArgumentException {
    // Verify that the input is valid.
    if (!FieldVerifier.isValidName(input)) {
      // If the input is not valid, throw an IllegalArgumentException back to
      // the client.
      throw new IllegalArgumentException(
          "Name must be at least 4 characters long");
    }

    // Escape data from the client to avoid cross-site script vulnerabilities.
    input = escapeHtml(input);

    // Delegate to SpringService and return the result
    return springService.echo(input);
  }

  /**
   * Escape an html string. Escaping data received from the client helps to
   * prevent cross-site script vulnerabilities.
   *
   * @param html the html string to escape
   * @return the escaped string
   */
  private String escapeHtml(String html) {
    if (html == null) {
      return null;
    }
    return html.replaceAll("&", "&").replaceAll("<", "<").replaceAll(
        ">", ">");
  }

   /**
    * Retrieves the SpringService bean
    */
 public SpringService getSpringService() {
  return springService;
 }

 /**
  * Assigns the SpringService bean
 */
 public void setSpringService(SpringService springService) {
  this.springService = springService;
 }

}
Notice we've declared a custom Spring service bean and added getters and setters. Whenever an RPC request is made to the GWT GreetingService interface, the application calls the service-side implementation, GreetingServiceImpl. This is the standard process with GWT RPC. However, we provided another flow in this cycle. After calling the GreetingServiceImpl, it then delegates to a SpringService bean for the actual retrieval of the output.

We need to create a new package in the project that corresponds to the package we declared in the gwt-servlet.xml. In my case I created org.krams.tutorial.service and created the following Spring service bean:

SpringService
package org.krams.tutorial.service;

import org.apache.log4j.Logger;

public class SpringService {

 protected static Logger logger = Logger.getLogger("service");
 
 public String echo(String msg) {
  logger.debug("Entering SpringService");
  
  return "Hello " + msg + " from Spring!";
 }
}
Here's the project structure:

Let's continue with the remaining XML configurations.

Here's spring-servlet.xml

spring-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:p="http://www.springframework.org/schema/p" 
 xsi:schemaLocation="http://www.springframework.org/schema/beans 
      http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
 
 <!-- Declare a view resolver -->
 <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver" 
      p:prefix="/WEB-INF/jsp/" p:suffix=".jsp" />

</beans>

Next, we declare the applicationContext.xml

applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:mvc="http://www.springframework.org/schema/mvc"
 xmlns:p="http://www.springframework.org/schema/p"
 xsi:schemaLocation="http://www.springframework.org/schema/beans 
            http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context-3.0.xsd
         http://www.springframework.org/schema/mvc 
         http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd" >

 <!-- Activates various annotations to be detected in bean classes -->
 <context:annotation-config />
 
 <!-- Scans the classpath for annotated components that will be auto-registered as Spring beans.
  For example @Controller and @Service. Make sure to set the correct base-package-->
 <context:component-scan base-package="org.krams.tutorial" />
 
 <!-- Configures the annotation-driven Spring MVC Controller programming model.
  Note that, with Spring 3.0, this tag works in Servlet MVC only!  
  Commented out because of conflict with GWTHandler 
  Instead we declare the elements declaratively!-->
 <!-- <mvc:annotation-driven /> -->
 
 <!-- This allows us to use @Controller and @Service annotations -->
 <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/>

 <!-- Commented out because of conflict with GWTHandler. You lost @ResponseBody,
  @RequestBody, @PathVariable
 <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
  <property name="webBindingInitializer">
   <bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer"/>
  </property>
  <property name="messageConverters">
   <list>
    <bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter" />
    <bean class="org.springframework.http.converter.StringHttpMessageConverter" />
    <bean class="org.springframework.http.converter.FormHttpMessageConverter" />
    <bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter" />
   </list>
  </property>
 </bean> -->

 <!-- Not really needed but it's part of the mvc:annotation-driven tag-->
 <bean id="conversion-service" class="org.springframework.format.support.FormattingConversionServiceFactoryBean" />
</beans>
The applicationContext.xml contains some interesting information. All the beans we've declared here aren't really required for our GWT application. However these beans enable us to use special annotations like @Service and @Controller. This allows us to have a Spring MVC application separate from the GWT application within this same project.

However, we cannot use the mvc:annotation-driven tag here because of a conflict with the GWTHandler. There are possible workarounds for these (I suggest you look at the comments in the configuration). Since we cannot declare the mvc:annotation tag, we declare its equivalent beans separately. However it turns out the real source of the conflict is the AnnotationMethodHandlerAdapter. It swallows all requests, and ignores the GWTHandler. Please bear that in mind.

Let's look again at the current project structure:

Notice we have four XML configurations. But also I have a highlighted the gwt-sl-1.1.jar. We need to create a lib folder and manually place a copy of this jar. Why? Because the author of this library doesn't support Maven yet. (See the discussion here)

That's it! We're done with all the required configuration. We've added and modified our classes as well. Let's run this application and see what we'll get.

To run the application, use the Maven gwt:run goal we've created from the previous tutorial: Spring and GWT Integration using Maven and GWTHandler (Part 1).

This is what see after running the application:


We changed the greeting from the typical server info message to a custom echo message.

Before we end this tutorial, let's preview our pom.xml. We'll compare the initial pom and the final pom.

pom.xml (initial, auto-generated)
<?xml version="1.0" encoding="UTF-8"?>
<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">

  <!-- POM file generated with GWT webAppCreator -->
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.krams.tutorial</groupId>
  <artifactId>spring-gwt-integration</artifactId>
  <packaging>war</packaging>
  <version>1.0.0-SNAPSHOT</version>
  <name>GWT Maven Archetype</name>

  <properties>
    <!-- Convenience property to set the GWT version -->
    <gwtVersion>2.1.0</gwtVersion>
    <!-- GWT needs at least java 1.5 -->
    <maven.compiler.source>1.5</maven.compiler.source>
    <maven.compiler.target>1.5</maven.compiler.target>
    <webappDirectory>${project.build.directory}/${project.build.finalName}</webappDirectory>
  </properties>

  <dependencies>
    <dependency>
      <groupId>com.google.gwt</groupId>
      <artifactId>gwt-servlet</artifactId>
      <version>2.1.0</version>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>com.google.gwt</groupId>
      <artifactId>gwt-user</artifactId>
      <version>2.1.0</version>
      <scope>provided</scope>
    </dependency>  
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.7</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <!-- Generate compiled stuff in the folder used for developing mode -->
    <outputDirectory>${webappDirectory}/WEB-INF/classes</outputDirectory>

    <plugins>

      <!-- GWT Maven Plugin -->
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>gwt-maven-plugin</artifactId>
        <version>2.1.0-1</version>
        <executions>
          <execution>
            <goals>
              <goal>compile</goal>
              <goal>test</goal>
              <goal>i18n</goal>
              <goal>generateAsync</goal>
            </goals>
          </execution>
        </executions>
        <!-- Plugin configuration. There are many available options, see gwt-maven-plugin 
          documentation at codehaus.org -->
        <configuration>
          <runTarget>gwtmodule.html</runTarget>
          <hostedWebapp>${webappDirectory}</hostedWebapp>
          <i18nMessagesBundle>org.krams.tutorial.client.Messages</i18nMessagesBundle>
        </configuration>
      </plugin>

      <!-- Copy static web files before executing gwt:run -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-war-plugin</artifactId>
        <version>2.1.1</version>
        <executions>
          <execution>
            <phase>compile</phase>
            <goals>
              <goal>exploded</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <webappDirectory>${webappDirectory}</webappDirectory>
        </configuration>
      </plugin>

    </plugins>
  </build>

</project>

pom.xml (final)
<?xml version="1.0" encoding="UTF-8"?>
<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">

  <!-- POM file generated with GWT webAppCreator -->
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.krams.tutorial</groupId>
  <artifactId>spring-gwt-integration</artifactId>
  <packaging>war</packaging>
  <version>1.0.0-SNAPSHOT</version>
  <name>GWT Maven Archetype</name>

  <properties>
    <!-- Convenience property to set the GWT version -->
    <gwtVersion>2.1.0</gwtVersion>
    <!-- GWT needs at least java 1.5 -->
    <maven.compiler.source>1.5</maven.compiler.source>
    <maven.compiler.target>1.5</maven.compiler.target>
    <webappDirectory>${project.build.directory}/${project.build.finalName}</webappDirectory>
  </properties>

  <dependencies>
    <dependency>
      <groupId>com.google.gwt</groupId>
      <artifactId>gwt-servlet</artifactId>
      <version>2.1.0</version>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>com.google.gwt</groupId>
      <artifactId>gwt-user</artifactId>
      <version>2.1.0</version>
      <scope>provided</scope>
    </dependency>  
   <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.8.1</version>
    <type>jar</type>
    <scope>compile</scope>
   </dependency>
   <dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-web</artifactId>
     <version>3.0.5.RELEASE</version>
     <type>jar</type>
     <scope>compile</scope>
    </dependency>
    <dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-core</artifactId>
     <version>3.0.5.RELEASE</version>
     <type>jar</type>
     <scope>compile</scope>
    </dependency>
    <dependency>
     <groupId>log4j</groupId>
     <artifactId>log4j</artifactId>
     <version>1.2.14</version>
     <type>jar</type>
     <scope>compile</scope>
    </dependency>
    <dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-tx</artifactId>
     <version>3.0.5.RELEASE</version>
     <type>jar</type>
     <scope>compile</scope>
    </dependency>
    <dependency>
     <groupId>jstl</groupId>
     <artifactId>jstl</artifactId>
     <version>1.1.2</version>
     <type>jar</type>
     <scope>compile</scope>
    </dependency>
    <dependency>
     <groupId>taglibs</groupId>
     <artifactId>standard</artifactId>
     <version>1.1.2</version>
     <type>jar</type>
     <scope>compile</scope>
    </dependency>
    <dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-webmvc</artifactId>
     <version>3.0.5.RELEASE</version>
     <type>jar</type>
     <scope>compile</scope>
    </dependency>
    <dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-aop</artifactId>
     <version>3.0.5.RELEASE</version>
     <type>jar</type>
     <scope>compile</scope>
    </dependency>
  </dependencies>

  <build>
    <!-- Generate compiled stuff in the folder used for developing mode -->
    <outputDirectory>${webappDirectory}/WEB-INF/classes</outputDirectory>

    <plugins>

      <!-- GWT Maven Plugin -->
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>gwt-maven-plugin</artifactId>
        <version>2.1.0-1</version>
        <executions>
          <execution>
            <goals>
              <goal>compile</goal>
              <goal>test</goal>
              <goal>i18n</goal>
              <goal>generateAsync</goal>
            </goals>
          </execution>
        </executions>
        <!-- Plugin configuration. There are many available options, see gwt-maven-plugin 
          documentation at codehaus.org -->
        <configuration>
          <runTarget>gwtmodule.html</runTarget>
          <hostedWebapp>${webappDirectory}</hostedWebapp>
          <i18nMessagesBundle>org.krams.tutorial.client.Messages</i18nMessagesBundle>
        </configuration>
      </plugin>

      <!-- Copy static web files before executing gwt:run -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-war-plugin</artifactId>
        <version>2.1.1</version>
        <executions>
          <execution>
            <phase>compile</phase>
            <goals>
              <goal>exploded</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <webappDirectory>${webappDirectory}</webappDirectory>
        </configuration>
      </plugin>

    </plugins>
  </build>

</project>

That's it. We're done. I hope you learned something new with this tutorial.

The best way to learn further is to try the actual application.

Download the project
You can access the project site at Google's Project Hosting at http://code.google.com/p/spring-mvc-gwt/

You can download the project as a Maven build. Look for the spring-gwt-integration.zip in the Download sections.

You can run the project directly using the Maven GWT plugin.
mvn gwt:run

If you want to learn more about Spring MVC and integration with other technologies, feel free to read my other tutorials in the Tutorials section.
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 2) ~ Twitter FaceBook

Subscribe by reader Subscribe by email Share

21 comments:

  1. Wonderful tutorial... I'm trying it out... I would like to do a GWT+Spring+JPA application for deploying in GAE... I'm totally newbie with GWT and GAE... I know spring since 2.0, but it could be a difficult task!! Thanks a lot for all the tutorials!!

    ReplyDelete
  2. @david, you're welcome. You're right. It's a difficult task. It would be great if Spring has "first class" support for GWT and GAE. Right now, support is provided via third party libraries and only with Spring Roo.

    ReplyDelete
  3. Really good stuff - thanks for that. Have been looking for a simple, up to date, Spring/GWT/Maven/Eclipse guide for a while now.

    ReplyDelete
  4. Thank you for the tutorial... I have been looking for an up to date tutorial on GWT and spring. I am new to the java world and especially Maven. I am wondering if my POM file should have been updated automatically or if I the only way to get the required dependencies into the file is to copy what you had in your "pom.xml (final)." Prior to copying your pom.xml I would get a "SERVICE_UNAVAILABLE" error. Thanks again!

    ReplyDelete
  5. I am new to spring ( coming from Struts / Java background) I want to use multiple datasource or my web application ( Converting from java to gwt ).
    How can I use your tutorial in my application .
    Let me describe my requirement.
    When user login using his email id , from “masterdatabase” you will get companyid.
    Depend on company ID , I need to access datasoruce “companyid_DS” .

    Any pointer/code appreciated.
    Thanks in advance.

    ReplyDelete
  6. Hi, when I import your project I'm getting the following error:
    "Plugin execution not covered by lifecycle configuration: org.codehaus.mojo:gwt-maven-plugin:2.1.0-1:generateAsync (execution: default, phase: generate-sources)"
    and
    Plugin execution not covered by lifecycle configuration: org.apache.maven.plugins:maven-war-plugin:2.1.1:exploded (execution: default, phase: compile)
    why thats happen?
    I search the reason but not found any solution
    :(

    ReplyDelete
  7. Hi , really good stuff but still want to know how to do this with annotations.In that case how we map multiple urls into a single controller to communicate with gwt

    ReplyDelete
  8. Can you please add a jsp page and a controller to the tutorial

    ReplyDelete
  9. Great article, I got a your example working and took it a bit further by adding security to it referencing blog spring-security-mvc-integration_18. One thing I notice is the the model values do not appear to come through. The login page has an error model reference, but the value is never realized on the page and simply dumps the literal string ${error} in the page

    ReplyDelete
  10. Hi Krams, thanks for the great article. It seems gwt-sl is now leaving in the central maven repo


    net.sf.gwt-widget
    gwt-sl
    1.3-RC1


    so you can update this tedious step of manually including the dependency.

    this is the discussion in the groups: http://groups.google.com/group/gwt-sl/browse_thread/thread/cf80f35b46d314d4

    ReplyDelete
  11. @dimitrisil, 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. Hi Krams,
    Thanks for the tutorial, this is the only step by step tutorial which I found after months of search on Google.
    I have done all your step and I could not get my project compile. I will get this message
    "[ERROR] /Users/bbiglari/gwt-maven-plugin/src/main/java/gwt/mvn/client/Messages.java:[9,7] duplicate class: gwt.mvn.client.Messages"

    Could you please help me to figure it out.
    my packages are gwt.mvn.*

    ReplyDelete
  13. @Bahador, I have written an updated version of this guide at http://krams915.blogspot.com/2012/02/spring-31-gwt-maven-plugin-and_3309.html

    Regarding your concern, it's possible that the GWT Maven plugin has auto-generated the Messages class. You have to delete the duplicate class (I would suggest deleting the one that you've created because Maven will auto-generate the Message class). If you check my updated tutorial, I believe I have covered that part.

    ReplyDelete
  14. hi ,
    Good post .
    Can we integrate GWT 1.0 and Spring?
    Could you please answer from which version GWT supports Spring integration


    ReplyDelete
  15. When I remove the "extends RemoteServiceSerlet" in GreetingServiceImpl class, I get 503 error

    ReplyDelete
  16. 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