Giving GWT a Spring in its Step

August 24, 2008

Some might claim that I’m rehashing a topic that has already been solved however I’m compelled to write this article as I personally struggled to connect all the disparate dots in order to make Google Web Toolkit (GWT) integrate with the Spring Framework. This is intended to be the article that I wished I’d stumbled upon in the first 10 minutes of looking for a solution to the problem. Before we start I’d also like to acknowledge that I’ve borrowed heavily from the concepts that people like George Georgovassilis pioneered. There’s nothing really new or groundbreaking here, I’ve simply combined all the knowledge that I’ve gained from all over the place into one convenient guide.

Update: Since publishing this article I’ve been contacted by Richard Bondi with regard to some great work that he’s also done on the matter of which I wish to also acknowledge his fantastic work. If you want to know more on this subject then I heartily recommend you check out his article on how to Integrate Spring with GWT and once you’ve done that, stubbing in hosted mode. Thanks again Richard.

Why would anyone want to integrate Spring and GWT?

If you’re familar with GWT (and I’m assuming you are) you may have marvelled, as I did, with how seamless and uncomplicated client-server interaction is. You are also probably aware that GWT RPC services are not web services. In fact they’re just plain old servlets that are endowed with an ability to serialize and deserialize information across the wire using a rather compact encoding developed by Google.

The RemoteServiceServlet class is great insofar as it handles all the grunt work of the RPC side of things whilst letting you get down to the business of writing your business logic for your services. The fact that you have to extend RemoteServiceServlet raises a few gnarly questions however:

1. What happens if I’ve already got my business logic implemented as an existing Java class with it’s own inheritance heirarchy?

2. What if you want to reuse that same class to implement a SOAP web service or any other RESTful interface for that matter?

3. What if I want to use the service class internally and don’t need all the RPC stuff?

4. What if something better than GWT comes out and I just want to replace the presentation layer technology?

Ouch! Suddenly extending RemoteServiceServlet starts to look a bit painful and far less useful than it did before. Now we could either try to imitate the ostrich and pretend that this isn’t an issue, or we could address the problem head on. We’re going to take the latter option.

Enter Spring

One answer to the above questions is to use a technique called Dependency Injection (DI). The Spring Framework happens to come with quite a good IoC container implementation and has become an industry standard. Without getting into the details about what DI is and how it works, Spring was designed with the intent of making your code as loosely coupled to its dependencies as possible and promoting POJO based development for enterprise applications.

So what does this look like in practice? Well currently out RPC model looks like this:

Standard GWT RPC plumbing

Standard GWT RPC plumbing (image courtesy of Google)

Ideally we want to look more like this:

New and improved GWT RPC plumbing with Spring integration

New and improved GWT RPC plumbing with Spring integration

Not too different really. With the exception of two new classes and two new interfaces you could be forgiven for thinking that I’d hardly done a thing, not to mention that three of them are Spring MVC classes! Well that’s actually the truth of it, I’ve done bugger all. It’s also worth noting that all the work is on the server-side with nothing new for the client.

Going back to our sample code, essentially all we need to do now is wire up our DispatcherServlet (a front-controller) and point it to our new GwtRpcController class for all RPC requests. We’ll also need to break the inheritance chain on the YourServiceImpl (a.k.a. QuoteServiceImpl) class to prove a point.

Getting down to business

In order to illustrate the point, I’m going to walk you through an adaptation of a random quote program from another GWT tutorial originally found on netbeans.org. I’ve adapted the original example to Eclipse as it’s my IDE of choice and I’m using Tomcat 6 as my test server.

For this tutorial you’ll require the following

If you’re impatient like me you might also want access to the project source code which can be found here. Please note that you’ll have to download the dependencies separately as I don’t want to inadvertently infringe on any copyright restrictions.

Okay so maybe I lied a little beforehand, there’s a bit more that we have to do in the way of re-jigging our project structure to make it all hang together and work. Anyway, time to cut some code!

Creating the project

Open the terminal/command line and go to the folder where you’ve unzipped the GWT SDK. And run the following command to create your eclipse project:

./projectCreator -ant gwt-wisdom -eclipse gwt-wisdom -out /home/dave/eclipse/workspace/gwt-wisdom

Note: replace the -out parameter argument with your own project destination. Also I’m using Linux, Windows users should just get rid of the preceeding “./” and change all forward slashes to back slashes and the commands will work just fine.

Now run this command to create your GWT project structure:

./applicationCreator -eclipse gwt-wisdom -out ~/eclipse/workspace/gwt-wisdom org.example.gwtwisdom.client.GwtWisdom

Again replace the -out parameter with the same location you used for the command above

Next import the new application into Eclipse using the File > Import menu option. Choose the Existing Projects option from under the General category and then browse to where ever you output the project files to.At this stage you should be able to hit run and test that the application skeleton is working.

Additional project setup

So that your application will compile once we start adding Spring into the mix add the the Spring framework and Spring Web MVC jars (spring.jar, spring-webmvc.jar) to your applications build path.

Now we need somewhere to put all our configuration files and deployment time dependencies. Create the following directory structure at the base of your project WebContent/WEB-INF/lib. This is almost identical to the Eclipse WTP project structure and will become useful later when we automate the project build with an Ant script.

In the WebContent/WEB-INF folder create a web.xml file an copy and paste the text below into it:

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.5"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
        http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

    <display-name>GWT Wisdom</display-name>

    <!-- Initialise the Spring MVC DispatcherServlet -->
    <servlet>
        <servlet-name>spring</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <!-- Map the DispatcherServlet to only intercept RPC requests -->
    <servlet-mapping>
        <servlet-name>spring</servlet-name>
        <url-pattern>*.rpc</url-pattern>
    </servlet-mapping>

    <welcome-file-list>
        <welcome-file>GwtWisdom.html</welcome-file>
    </welcome-file-list>

</web-app>

Now I’m aware that the integrated Tomcat instance that comes with GWT has a web.xml file but we can’t actually modify the Tomcat web.xml file as it is dynamically regenerated by the compiler every time we start hosted mode. Hence why we’re creating our own.

If you were paying attention in the last step you would have seen that we defined a servlet in the web.xml file. This is the Spring Web MVC DispatcherServlet which will intercept our RPC requests and route them to the correct service. Each DispatcherServlet instance requires a bean definition file of the same with a “-servlet.xml” suffix. So in the same folder create a file called spring-servlet.xml and copy and paste the following into it:

<?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-2.5.xsd">

    <!-- The application context definition for the DispatcherServlet -->

    <!-- Maps the request through to a concrete controller instance -->
    <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <value>
            /**/quote.rpc=quoteController
            </value>
        </property>
    </bean>

    <!-- GwtRpcController wraps our service in order to decode the incoming -->
    <!-- request then delegates processing of the call to the POJO service -->
    <!-- and then encodes the return value forwarding the response. -->
    <bean id="quoteController" class="org.example.gwtwisdom.server.GwtRpcController">
        <property name="remoteService">
            <bean class="org.example.gwtwisdom.server.QuoteServiceImpl" />
        </property>
    </bean>

</beans>

This will be used to configure the DispatcherServlet to route calls to our services. It does so via the SimpleUrlHandlerMapper which uses regular expression syntax to match the request url to a controller bean ID.

Now you’ll need to add the following jars to the WebContent\WEB-INF\lib folder: commons-logging.jar, gwt-servlet.jar, gwt-user.jar, spring.jar, spring-webmvc.jar. This is necessary for when it comes time to deploy the app.

Creating the RPC quote service

Next we’re going to create our RPC service. Start by creating a subpackage of the *.client package and call it “service”.

Create a new interface called QuoteService and make it look like the code below:

package org.example.gwtwisdom.client.service;

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

@RemoteServiceRelativePath("quote.rpc")
public interface QuoteService extends RemoteService {
    public String getQuote();
}

Those already familiar with GWT will know that the next step is to create an async service interface to pair with the QuoteService interface we just created. Create a new interface again in the *.client.service package called QuoteServiceAsync and modify it so it looks like the following:

package org.example.gwtwisdom.client.service;

import com.google.gwt.user.client.rpc.AsyncCallback;

public interface QuoteServiceAsync {
    public void getQuote(AsyncCallback<String> callback);
}

Enough of interfaces. Now it’s time to code up the actual service itself. Create a new package under the org.example.gwtwisdom package called server. Once that’s done create a new class and call it QuoteServiceImpl.

package org.example.gwtwisdom.server;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import org.example.gwtwisdom.client.service.QuoteService;

public class QuoteServiceImpl implements QuoteService {

    private Random randomizer = new Random();
    private static List<String> quotes = new ArrayList<String>();

    static {
        quotes.add("No great thing is created suddenly - Epictetus");
        quotes.add("Well done is better than well said - Ben Franklin");
        quotes.add("No wind favors he who has no destined port - Montaigne");
        quotes.add("Sometimes even to live is an act of courage - Seneca");
        quotes.add("Know thyself - Socrates");
    }

    public String getQuote()
    {
        return quotes.get(randomizer.nextInt(quotes.size()));
    }

}

Now some of you might be saying to yourselves “hey wait a minute, don’t we have to extend RemoteServiceServlet?”. Well read on. I’m about to show you a magic trick straight out of the Gang of Four (GoF) playbook.

To cap it all off before we continue, we should probably update our module configuration file to include our new service mapping. Copy and paste the following into your GwtWisdom.gwt.xml file:

<!-- RPC service servlet declarations                             -->
<servlet path="/quote.rpc"
    class="org.example.gwtwisdom.server.QuoteServiceImpl"/>

All rise for the GwtRpcController

Here’s the fun part, now we’re going to create the GwtRpcController. In the org.example.gwtwisdom.server package create a class called, you guessed it GwtRpcController. Then copy and paste the following code into it:

package org.example.gwtwisdom.server;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.context.ServletContextAware;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

import com.google.gwt.user.client.rpc.IncompatibleRemoteServiceException;
import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.SerializationException;
import com.google.gwt.user.server.rpc.RPC;
import com.google.gwt.user.server.rpc.RPCRequest;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;

public class GwtRpcController extends RemoteServiceServlet implements
        Controller, ServletContextAware {

    private ServletContext servletContext;

    private RemoteService remoteService;

    private Class remoteServiceClass;

    public ModelAndView handleRequest(HttpServletRequest request,
            HttpServletResponse response) throws Exception {
        super.doPost(request, response);
        return null;
    }

    @Override
    public String processCall(String payload) throws SerializationException {
        try {

            RPCRequest rpcRequest = RPC.decodeRequest(payload,
                    this.remoteServiceClass);

            // delegate work to the spring injected service
            return RPC.invokeAndEncodeResponse(this.remoteService, rpcRequest
                    .getMethod(), rpcRequest.getParameters());
        } catch (IncompatibleRemoteServiceException ex) {
            getServletContext()
                    .log(
                            "An IncompatibleRemoteServiceException was thrown while processing this call.",
                            ex);
            return RPC.encodeResponseForFailure(null, ex);
        }
    }

    @Override
    public ServletContext getServletContext() {
        return servletContext;
    }

    public void setServletContext(ServletContext servletContext) {
        this.servletContext = servletContext;
    }

    public void setRemoteService(RemoteService remoteService) {
        this.remoteService = remoteService;
        this.remoteServiceClass = this.remoteService.getClass();
    }

}

This class works on the principle that it is both a RemoteServiceServlet AND a Spring MVC Controller (don’t you just love polymorphism?) meaning that it can not only be used as a target by the DispatcherServlet for handling incoming RPC requests, but also to decode the incoming RPC requests. Remember I previously mentioned the Gang of Four? Well you’re looking right at the strategy pattern baby. Pretty cool huh?

Upon receiving a request we delegate handling of this to the Controller’s superclass (the RemoteServiceServlet) to handle the unmarshalling of the request. We then intercept the processing of the message by overriding RemoteServiceServlet.processCall method and delegate the processing to the RemoteService POJO.

Where did we get this magical POJO from you ask? Well we injected it into the class via the setRemoteService setter back in the spring-servlet.xml bean definition file earlier.

Okay one last thing before we continue on to preparing the app for deployment. We need to tie all of this together by doing some work to display our quotes in the GWT entry point class and fixing up some of the HTML.

In the GwtWisdom.html file copy and paste the following in below the body tag:

<p>
This is an AJAX application that retrieves a random quote from
the Random Quote service every three seconds. The data is retrieved
and the quote updated without refreshing the page!
</p>

Once you’ve done that, replace the method body of the GwtWisdom classes onModuleLoad method with the following:

    public void onModuleLoad() {
        final Label quoteText = new Label();

        Timer timer = new Timer() {

            public void run() {
                // create an async callback to handle the result:
                AsyncCallback<String> callback = new AsyncCallback<String>() {

                    public void onFailure(Throwable t) {
                        // display error text if we can't get the quote:
                        quoteText.setText("Failed to get a quote");
                    }

                    public void onSuccess(String result) {
                        // display the retrieved quote in the label:
                        quoteText.setText(result);
                    }
                };
                QuoteServiceAsync service = (QuoteServiceAsync) GWT
                        .create(QuoteService.class);
                service.getQuote(callback);
            }
        };

        timer.scheduleRepeating(3000);
        RootPanel.get().add(quoteText);
    }

Note: since this is client-side code be careful that you use the google timer implementation as opposed to the stock Java one otherwise it won’t work like you expect.

That should take care of the display side of things. If you want you can also jazz it up a bit by putting some styles in the GwtWisdom.css file.

Ditching the GWT tomcat server

Remember that earlier on we created our own custom web.xml to initialise the Spring context via a DispatcherServler? Well because of this we can no longer rely upon the integrated tomcat server that comes with GWT to run our app. Fortunately the hosted mode browser comes with a -noserver switch which allows us to configure it to use the server of our choice during development.

There’s a bit of a knack to getting this running all running nice and seamlessly within Eclipse. First we’re going to have to compile the application then package it up and deploy it to the server just this once just so the server has knowledge of your app. Don’t worry, once it’s running in hosted mode the app will use your workspace code, but trust me we need to do this just once.

I’m actually going to use Ant to build and package the app. Conveniently, this is going to work out great in future when I need to bundle the app up into a war file and deploy it elsewhere.

First create a file called build.xml in the root of your project and copy and paste the script below into the build file.

<?xml version="1.0" encoding="utf-8"?>
<project name="gwt-wisdom" default="compile" basedir=".">
    <description>
        Build file. This is used to package up your project as a war, if you
        want to distribute/deploy it. This isn't needed for normal operation.
    </description>

    <property file="build.number"/>

    <!-- GWT properties - change these to suit your distribution (i.e. windows, mac or linux) -->
    <property name="platform" value="linux"/>
    <property name="gwt.home" value="/home/dave/eclipse/lib/gwt/linux/1.5.1"/>

    <!-- Build properties - shouldn't need changing -->
    <property name="name" value="GwtWisdom"/>
    <property name="module" value="org.example.gwtwisdom.GwtWisdom"/>
    <property name="src.dir" value="src"/>
    <property name="web.dir" value="WebContent"/>
    <property name="lib.dir" value="${web.dir}/WEB-INF/lib"/>
    <property name="bin.dir" value="${web.dir}/WEB-INF/classes"/>
    <property name="test.dir" value="test"/>
    <property name="out.dir" value="build"/>
    <property name="dist.dir" value="dist"/>

    <!-- set classpath -->
    <path id="project.class.path">
        <pathelement path="${java.class.path}/"/>
        <pathelement path="${lib.dir}/gwt-user.jar"/>

        <!-- Additional dependencies go here -->
        <pathelement path="${lib.dir}/spring.jar"/>
        <pathelement path="${lib.dir}/spring-webmvc.jar"/>
        <pathelement path="${lib.dir}/commons-logging.jar"/>
    </path>

    <target name="clean">
        <delete file="${dist.dir}/${name}.war"/>
        <!-- Delete the bin directory tree -->
        <delete>
            <fileset dir="${bin.dir}" includes="**/*.class"/>
        </delete>
    </target>

    <target name="compile" description="Compile both client &amp; server code">
        <!-- cross-compile client-side java classes -->
        <mkdir dir="${out.dir}"/>
        <java classname="com.google.gwt.dev.GWTCompiler" dir="${basedir}" fork="true">
            <jvmarg value="-Xmx256M"/>
            <classpath>
                <pathelement path="${java.class.path}"/>
                <pathelement location="${src.dir}"/>
                <pathelement location="${bin.dir}"/>
                <pathelement path="${gwt.home}/gwt-user.jar"/>
                <pathelement path="${gwt.home}/gwt-dev-${platform}.jar"/>
            </classpath>
            <arg line="-out ${basedir}/${out.dir}"/>
            <arg value="%*"/>
            <arg value="${module}"/>
        </java>
        <copy todir="${web.dir}">
            <fileset dir="${out.dir}/${module}"/>
        </copy>

        <!-- compile server-side java classes -->
        <mkdir dir="${web.dir}/WEB-INF/classes"/>
        <javac srcdir="${src.dir}:${test.dir}" destdir="${bin.dir}" includes="**" debug="on" debuglevel="lines,vars,source" source="1.5">
            <classpath refid="project.class.path"/>
        </javac>
    </target>

    <target name="package" depends="compile" description="Package up the project as a war">
        <mkdir dir="${dist.dir}"/>
        <war destfile="${dist.dir}/${name}.war" webxml="${web.dir}/WEB-INF/web.xml">
            <fileset dir="${out.dir}/${module}">
                <include name="**/*.*"/>
            </fileset>
            <fileset dir="${web.dir}">
                <include name="**/*.*"/>
                <exclude name="WEB-INF/web.xml"/>
            </fileset>
        </war>
    </target>

    <target name="all" depends="package"/>

</project>

Run the build script using the package target (Alt+Shift+X then Q). Alternatively if you’re using Ant from the command line then running “ant package” from the project directory should do the trick. This should compile and package the app automatically for you into a war file.

If the build fails for any reason you might have to edit some of the property elements listed at the top of the file depending on your platform (windows, mac or linux) and where you unzipped your GWT libs. Just change these as appropriate and everything should work fine.

From here you can just go ahead and fire up Tomcat and deploy the war file onto the app server either via the admin console or the autodeploy directory. At this point you should be able to test your application by opening your web browser and navigating to http://localhost:8080/GwtWisdom/GwtWisdom.html. If this works then we’re all good to proceed to the next stage.

Getting hosted mode to run with -noserver

Okay we’re getting close now. This step isn’t essential really, what I’ve shown you so far should be more than enough to demonstrate the application in action. If however you want to continue debugging and testing your app in hosted mode for development like I do then read on.

We’re going to need to edit the launch configuration in order to run the app in hosted mode using our own Tomcat instance as opposed to the integrated Tomcat server. You can do this one of two ways, either edit the GwtWisdom.launch file directly or you edit them via the Eclipse run configuration manager. We’re going to do it via the run configuration manager.

You can open the manager by right-clicking on the project Run As > Run Configurations. Once there, you should see in the left-hand tree view under Java Applications the GwtWisdom launch configuration. Select it and then click the Arguments tab over on the right hand side. Check that the program arguments resemble those below. Your configuration may differ slightly as far as the port is concerned but should read something like:

-out www GwtWisdom/GwtWisdom.html
-noserver
-port 8080

This configuration tells the hosted mode browser to use an external server on the given port and where it should find your applications home page on the server.

You might also have to add the contents of your WebContent/WEB-INF/lib folder to the classpath tab in order to get it working but try it first by clicking apply and then run.

Sweet sweet success!

All that’s left to do is run the project. If you’ve configured it correctly it should fire up the app in all its hosted glory. Your services are now free from the tyranny of RemoteServiceServlet!

Now if only we could figure out a way to remove the dependency on the QuoteService interface from the service. Then it really would be a bona-fide POJO…another day, another challenge.

114 Responses to “Giving GWT a Spring in its Step”


  1. […] Kuhn has put together a comprehensive guide to piecing together GWT and Spring, a nice recipe for the Java heads among […]


  2. […] Kuhn has put together a comprehensive guide to piecing together GWT and Spring, a nice recipe for the Java heads among […]

  3. Kent Says:

    Very nice article! It’s about time there were a comprehensive how-to on this subject.


  4. […] Kuhn has put together a comprehensive guide to piecing together GWT and Spring, a nice recipe for the Java heads among […]


  5. […] Kuhn has put together a comprehensive guide to piecing together GWT and Spring, a nice recipe for the Java heads among […]

  6. Amber Says:

    Wow! This has really helped me. Thanks so much for putting this up for us to use! Well DONE!

  7. Richard Bondi Says:

    Similar solutions were previously published on the google incubator site:

    Integrate Spring with GWT.

    And once you’ve done that, stubbing in hosted mode.

    /r:b:

  8. David Kuhn Says:

    Thanks for the feedback Richard.

    Yes I was aware of all of this and I never attempted to take credit for the work done by others. As I originally stated; I was compelled to write this how-to as I hadn’t yet found anything that tied all the parts together in one convenient guide. Furthermore many of the examples are done in rather abstract form. It’s my hope that by putting it in the context of a full fledged project, that you can download with source code and all, would foster greater understanding.

    Incidently your original post will not work without modification on GWT 1.5. You need to implement the ServletContextAware interface from the Spring libraries and override the getServletContext() method in order for it to work.


  9. […] that convenient either if you’re an Eclipse user. If you’ve read my previous post on Integrating Spring with GWT you would have seen that we still had to manually package and deploy the application to the app […]

  10. Sakuraba Says:

    This approach can become ugly when you have many different GWT-RPC interfaces in a multi-module scenario, because all of the implementing classes will have to be injected inside the “GwtRpcController” which then needs logic to find out which service to dispatch, too.

    Or am i mistaken?


  11. […] Giving GWT a Spring in its Step « Technophiliac (tags: spring java integration gwt) […]


  12. […] Giving GWT a Spring in its Step « Technophiliac (tags: spring java integration gwt) […]

  13. David Kuhn Says:

    Hi Sakuraba,

    Thanks for the question. I’m not sure I completely understand but here goes.

    The GwtRpcController doesn’t require any modification whatsoever. All the mapping/routing RPC calls to the various services you might have is performed by the DispatcherServlet and the SimpleUrlMapperHandler class. These rules are completely confined to the bean context file which you define for the DispatcherServlet. No modification of the code is necessary.

    The GwtRpcController has a 1 to 1 relationship with the RemoteService. If you wish to implement another service. Then you must define another instance of the GwtRpcController via the bean context.

    If you’re worried about the bean context getting a bit heavy, you can always define other application contexts for your application’s layers to break it up a bit.

    Does that answer the question?

    Dave

  14. George Georgovassilis Says:

    Hello Dave

    Nice article – just like you, I’d also wish this were my first 10 minutes with Spring and GWT 😉
    The approach you take is the most intuitive many people (including aforementioned GWT incubator) take, but it may at times be impractical. The whole point is to public business objects (POJOs) to the RPC protocol. The fact that services must now bind to a 3rd party API by implementing the RemoteService interface breaks sepparation of concerns, even if it is just an interface and is a side effect (a sinful path annotations walk on also btw).

    There are actually two ways around this:

    1. Create a copy interface that declares all interesting methods of your POJO service and then create a class that extends the service and implements the interface. This new class can then be exported to RPC

    2. In the SL we implemented a dynamic binding: you provide a POJO class, you create an interface and the SL will bind them in runtime together for you


  15. Excellent post, yes, I wish it were there too when I was looking for a way to integrate Spring with GWT (had to figure it out the hard way….)

    Not to mention, I work for Google, so it’s always nice to see that people like our stuff and ‘get it’ 🙂

    A minor nit-pick: at first, I was unable to compile the server-side classes, and had to modify the ant file as follows:

    1. add a variable to point to Tomcat’s shared libs:

    2. add servlet-api.jar to the build path:


    there’s no need to add servlet-api.jar in the WEB-INF/lib dir, as Tomcat will provide those classes for you at runtime

    3. you only need to compile the server classses, not everything:

    [in a real-world app, it’s likely you would have ‘shared’ Java classes – most likely somewhere like org.example.gwtwisdom.shared.* – so you would add those here too]

    The one real issue here, however, is that you can’t debug the server-side classes from within Eclipse – only the client-side classes are available for inspection when running hosted mode.

    The one solution (I am guessing here, as I haven’t tried it myself yet) would be to run two instances of Eclipse, one running the app inside an Eclipse-configured Tomcat instance (although, it may get a bit awkward how to deploy the classes / scripts).

    Would be good to know if you’ve found a solution to this.


  16. […] Giving GWT a Spring in its Step Although there are other guides out there, David Kuhn has written a nice article on integrating GWT and Spring. […]

  17. rccgmr Says:

    I think I followed all the instructions but I get two alerts from Eclipse, in GwtRpcController.java: “the serializable class GwtRpcController does not declare a static final serialVersionUID field of type long” (in line 18); “Class is a raw type. References to generic type Class should be parameterized” (in line 25). And I get this failure response in GwtWisdom execution: “Failed to get a quote”. Can someone explain to me what can I do to fix this?

  18. David Kuhn Says:

    They’re two very strange errors to be having. I have to ask; Why is eclipse complaining that the GwtRpcController needs a serialVersionUID field? This class isn’t intended to be serializable. Furthermore, this class isn’t generic so it should require any such declaration of type.

    Have you changed the class at all from the example?

  19. rccgmr Says:

    No. I just get the files from the package war. But even if I copy & paste the code from this article, I get the same alerts. I thought that could be a Eclipse bug, but the application doesn´t work directly in Tomcat too, returning the failure message I said.

  20. rccgmr Says:

    Some help please send to rcc.gmr@gmail.com

  21. rccgmr Says:

    Well, I get this running! Eclipse still shows alerts in GwtRpcController.java, but they aren´t relevant for the execution of the application.
    The problem was in build.xml, where I forgot to change some paths. It´s everything ok, now.
    Thanks David for this article. It´s excellent.

  22. David Kuhn Says:

    My apologies rccgmr, I just checked the code again and you’re right I am getting those warnings. As you said though, it shouldn’t affect the operation of the code, but may stop you from compiling depending on how aggressive you have your compiler set (i.e. treat warnings as errors).

  23. Andrew Skene Says:

    Very nice post, it made setting things up pretty easy. I ran into some issues with the serialization policy when using files implementing Serializable instead of isSerializable. It wouldn’t find/load the autogenerated .gwt.rpc serialization whitelist. I had to make the following change to get it to work:

    @Override
    public String processCall(String payload) throws SerializationException {
    try {

    RPCRequest rpcRequest = RPC.decodeRequest(payload,
    this.remoteServiceClass, this);

    // delegate work to the spring injected service
    return RPC.invokeAndEncodeResponse(this.remoteService, rpcRequest
    .getMethod(), rpcRequest.getParameters(), rpcRequest.getSerializationPolicy());
    } catch (IncompatibleRemoteServiceException ex) {
    getServletContext()
    .log(
    “An IncompatibleRemoteServiceException was thrown while processing this call.”,
    ex);
    return RPC.encodeResponseForFailure(null, ex);
    }
    }

  24. x Says:

    I was also getting the “Failed to get a quote” error – but then I realised that I hadn’t read the acticle closely enough. I was using Tomcat 5.5.26. As soon as I moved to Tomcat 6.0.18 – it worked!. x.

  25. David Kuhn Says:

    Thanks Andrew, yeah I’ve since run into that problem after upgrading from RC2 to the final GWT 1.5 release. Thanks for posting the solution. I’ll update the article when I get a chance.

  26. Pope Says:

    Nice Article!

    I would like to add that GwtWisdom.gwt.xml doesn’t need and more importantly, should not have the sevlet defined. That is supposed to be used when you’re using the internal Tomcat with GWT and moreover, QuoteServiceImpl doesn’t extend RemoteServiceServlet.

    @rccgmr

    Those two warning that you’re getting, when you’re defining your variables, try using this:


    private static final long serialVersionUID = 1L;

    private ServletContext servletContext;
    private RemoteService remoteService;
    private Class remoteServiceClass;

    The first line should clear up your serialization problem because RemoteServiceServlet extends HttpServlet, and HttpServlet implements Serializable. The last line should clear up your “Class is a raw type. References to generic type Class should be parameterized” problem.

    For future problems like that, if you hit cnt+1 or cmd+1 on a mac, Eclipse will give you options on how to fix things like that.

  27. Pope Says:

    Crap….some of the stuff I wrote had some bad formatting.

    private Class remoteServiceClass;

    should read

    private Class<? extends RemoteService> remoteServiceClass;

  28. Razi Alqasem Says:

    thanks for the interesting and useful topic
    i try to do the project step by step , everything work fine until i tried to run my application in the host mode using my eclipse run manager ..don’t i need to tell the GWT host where my tomcat is located ??

  29. meg Says:

    in the host mode the web.xml is generated by the GWTshell so what to do so i can run my application in the host mode?? how can i tell the GWTshell to use my web.xml ??

  30. Fred Says:

    Thank you for taking the time to write this article. It was a big help as I learn GWT-Spring integration. Let me see if I can reciprocate for folks who may have had the same problem I had.

    With your example source, the onFailure() kept getting invoked in the callback for me. Further inspection found that it “could not find the spring servlet”. I’m not sure if I used a cannon to kill a mosquito, but here is what I ended up doing to get the GWTWisdom example to work for me in a nutshell:

    – Downloaded the GWT Server Library (http://gwt-widget.sourceforge.net/). I used version 0.1.5a.
    – Integrated their JAR files (specifically gwt-sl-0.1.5a.jar and commons-logging-1.1jars) into my WEB-INF/lib and used their handler instead of your custom written GwtRpcController.
    – Modified my web.xml and spring-servlet.xml files to map to these new classes. It slimmed down the complexities a bit I think. The gwt-sl JAR file complained of a lack of application context XML file, so I went ahead and created an applicationContext.xml and moved the QuoteServiceImpl bean mapping over to it.

    And that’s it, seems to run fine. I didn’t try this in hosted mode, I just used a fully built WAR and dropped it into an external Tomcat 6.0.18 server. For completeness, I’m using Eclipse (Ganymede) and GWT 1.5.2 (on Windows).

    If you are also suffering from this problem, my solution may help. If you are like me, you would probably find a working source far more helpful than my chatter above, so here it is: http://dl.getdropbox.com/u/114750/gwt-wisdom.zip

    Hope this helps.. thanks again for the time it took to write this tutorial.

  31. Fred Says:

    Dropbox’s public HTML link seems to be broken at the time of this writing, so if you have problems with the above link you can grab it here:

    http://www.fredhat.com/stuff/gwt-wisdom.zip

  32. Andy Thomas Says:

    Hi I’ve been getting this error on my mac (using eclipse)


    Buildfile: /Users/andrewthomas/Documents/projects/gwt-wisdom/build.xml
    compile:
    [java] Exception in thread "main" java.lang.NoClassDefFoundError: com/google/gwt/dev/GWTCompiler
    [java] Java Result: 1
    BUILD SUCCESSFUL
    Total time: 686 milliseconds

    I’ve tried every which way to get it going but dont seem to be able to do it. I’ve basically just downloaded the raw source code.

    My new build file looks like this


    Buildfile: /Users/andrewthomas/Documents/projects/gwt-wisdom/build.xml
    compile:
    [java] Exception in thread "main" java.lang.NoClassDefFoundError: com/google/gwt/dev/GWTCompiler
    [java] Java Result: 1
    BUILD SUCCESSFUL
    Total time: 686 milliseconds

    Any Ideas, it’s driving me nuts 🙂

  33. Andy Thomas Says:

    Sorry this is my build.xml

    Build file. This is used to package up your project as a war, if you
    want to distribute/deploy it. This isn't needed for normal operation.

  34. David Kuhn Says:

    Hey Andy,

    I’d suggest you check that the gwt.home property at the top of the build file is pointing to your copy of GWT. Also check that the platform property is set to windows, linux or mac depending on what you’re developing on.

    The error your getting relates to java not being able to find the GWT compiler on the classpath. Providing you’ve made no other significant changes to the build file, following the above instructions should solve your problem.

    Regards,

    Dave

  35. Andy Thomas Says:

    Hi Dave

    Thanks, my bad. I’d done everything you said above earlier I’d just forgotten to copy the lib jar files into the WEB-INF structure …. that’ll teach me to follow instructions properly 🙂

    It works an absolute treat!!! great article, fantastic for newbies like me

    Any

  36. Ed Says:

    Hi all,
    Very nice article. I am using Maven2 instead of Ant to build the project, and I get the next runtime error in GWT Shell console: “Not compatible with HttpSevlet: org.example.gwtwisdom.server.QuoteServiceImpl (does your service extend RemoteServiceServlet?) Unable to dispath request”. In the browser: “Failed to get a quote”. I think I`ve not configure the pom.xml correctly:

    com.totsp.gwt
    maven-googlewebtoolkit2-plugin
    2.0-beta24

    ${basedir}/src/main/webapp/WEB-INF/web.xml
    INFO

    org.example.gwtwisdom.GwtWisdom

    org.example.gwtwisdom.GwtWisdom/GwtWisdom.html
    DETAILED
    false
    -Xmx512m

    ${gwtVersion}

    mergewebxml
    gwt
    compile

    Thank you very much

  37. abhishek Says:

    great tutorial, i am able to do it one hour……..thanks

  38. gwtnoob Says:

    great job!

    I just have one concern. Let’s say I added a property ‘author’ on QuoteServiceImpl. If I inject a value for the property ‘author’ from the spring-servlet.xml, how can I get the value of the ‘author’ from QuoteServiceImpl?

    public class QuoteServiceImpl extends RemoteServiceServlet implements QuoteService {
    private String author;
    ….
    public Quote getQuote()
    {
    System.out.println(author); // what will be the value of author here?
    return new Quote(quotes.get(randomizer.nextInt(quotes.size())));
    }

    public void setAuthor(String author){
    this.author = author;
    }

    }

    added/modified in to spring-servlet.xml

    thanks.

  39. gwtnoob Says:

    added/modified in spring-servlet.xml:

  40. DanG Says:

    Now that it’s December of 2008, and presumably things change fairly often, is this still the preferred way to integrate Spring + GWT 1.5?

    I would love to know before I begin this endeavor. Thank you

  41. Wilfred Says:

    What about having Spring in the client as well? Do you think this would work?

    http://springframework.me/

  42. Pseudonym Says:

    Great informative article . Very useful to add.

    Just to add more about spring annotations too ( since 2.5 release ) – we can specify as follows.

    In spring-servlet.xml –

    GwtRpcController,java :
    ===============

    This could injected via annotation as follows.

    import org.springframework.stereotype.Service;
    import org.springframework.beans.factory.annotation.Autowired;

    @Service(“loginController”)
    public class GwtRpcController extends RemoteServiceServlet .. {

    @Autowired
    private RemoteService remoteService;

    .
    .
    .
    }

    QuoteServiceImpl.java:
    ================

    @Service(“remoteService”)
    public class QuoteServiceImpl implements QuoteService {

    }

    This gets rid of the bean configuration and playing around with annotations only from hereon.

  43. sahlouls Says:

    Hello, I followed this tutorial and very glad to use Spring and GWT RPC.
    But, I need the HttpSession inside my RPC server implementation.
    It doesn’t really work.
    Help !!!

  44. David Kuhn Says:

    Hi sahlouls,

    Getting access to the HttpSession object isn’t difficult but it requires you to modify the GwtRpcController slightly. Firstly you’ll need to create an interface called SessionAware. This interface has one method defined:

    void setSession(HttpSession session);

    Secondly you’ll need to implement this interface within your server side RemoteService implementation so that you can inject the session object.

    Lastly you’ll need to modify the GwtRpcController service to check if the injected RemoteService instance is also an instance of SessionAware like so:

    // inject session variable into remote services handler if session aware
    if (remoteService instanceof SessionAware) {
    ((SessionAware) remoteService).setSession(request.getSession());
    }

    This needs to go between the decode step and before the invokeAndEncodeResponse in the processCall method.

    Dave.

  45. Cristian Says:

    Hi,

    I’m new to GWT and I was trying to get a simple app that will use GWT+Spring+Maven. I was able to find a suitable example on the internet for GWT+Spring+Maven, that also work. THe issue is that when I’m trying to define new beans and inject them in the exsiting GWT ones, the DI doesn’t work as expected. I am getting no errors though, just null values.

    The example was taken from this site. I had to tweak it a little bit to work properly. To that app I was trying to add a BO layer and a DAO layer.

    Any suggestions how could I register&inject those beans (myObjectDAO and myObjectBO) into “quoteService”? “quoteService” bean is registered and injected properly in “quoteController”. I do have the setters properly in place for the properties in the bean class, otherwise spring would complained.

    Thank you.
    ===========================================================
    service-context.xml
    ===========================================================

    classpath:service-placeholder.properties

    <!–

    –>

    ===========================================================
    spring-servlet.xml
    ===========================================================

    /**/quote.rpc=quoteController



    ===========================================================
    web.xml
    ===========================================================

    Sample

    index.html

    contextConfigLocation

    classpath:service-context.xml,
    classpath:spring-servlet.xml

    org.springframework.web.context.ContextLoaderListener

    <!–

    org.springframework.web.context.request.RequestContextListener

    –>

    spring

    org.springframework.web.servlet.DispatcherServlet

    1

    spring
    *.rpc

  46. Cristian Says:

    I’ll post again the code:

    ===========================================================
    service-context.xml
    ===========================================================
    <?xml version=”1.0″ encoding=”UTF-8″?>
    <!DOCTYPE beans PUBLIC “-//SPRING//DTD BEAN//EN” “http://www.springframework.org/dtd/spring-beans.dtd”>
    <beans>
    <bean id=”quoteService” class=”com.totsp.sample.client.QuoteServiceImpl”>
    <property name=”myObjBO”>
    <ref bean=”myObjectBO” />
    </property>
    </bean>
    <bean id=”salesproServicePlaceholder” class=”org.springframework.beans.factory.config.PropertyPlaceholderConfigurer”>
    <property name=”ignoreUnresolvablePlaceholders” value=”true”/>
    <property name=”location”>
    <value>classpath:service-placeholder.properties</value>
    </property>
    </bean>

    <bean id=”myObjectDAO” class=”com.totsp.sample.dao.MyObjectDAOImpl”>
    <!–
    <property name=”sqlMapClient”>
    <ref bean=”sqlMapClient” />
    </property>
    –>
    </bean>

    <bean id=”myObjectBO” class=”com.totsp.sample.bo.MyObjectBOImpl”>
    <property name=”myObjectDAO”>
    <ref bean=”myObjectDAO” />
    </property>
    </bean>
    </beans>

    ===========================================================
    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”
    xsi:schemaLocation=”http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-2.5.xsd“>

    <!– The application context definition for the DispatcherServlet –>

    <!– Maps the request through to a concrete controller instance –>
    <bean id=”urlMapping” class=”org.springframework.web.servlet.handler.SimpleUrlHandlerMapping”>
    <property name=”mappings”>
    <value>
    /**/quote.rpc=quoteController
    </value>
    </property>
    </bean>

    <!– GwtRpcController wraps our service in order to decode the incoming –>
    <!– request then delegates processing of the call to the POJO service –>
    <!– and then encodes the return value forwarding the response. –>
    <bean id=”quoteController” class=”com.totsp.sample.client.GwtRpcController”>
    <property name=”remoteService”>
    <ref bean=”quoteService” />
    </property>
    </bean>
    </beans>

    ===========================================================
    web.xml
    ===========================================================
    <?xml version=”1.0″ encoding=”UTF-8″?>

    <web-app version=”2.4″ xmlns=”http://java.sun.com/xml/ns/j2ee”
    xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
    xsi:schemaLocation=”http://java.sun.com/xml/ns/j2ee
    http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd“>
    <display-name>Sample</display-name>

    <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    </welcome-file-list>

    <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
    classpath:service-context.xml,
    classpath:spring-servlet.xml
    </param-value>
    </context-param>

    <listener>
    <listener-class>
    org.springframework.web.context.ContextLoaderListener
    </listener-class>
    </listener>
    <!–
    <listener>
    <listener-class>
    org.springframework.web.context.request.RequestContextListener
    </listener-class>
    </listener>
    –>
    <servlet>
    <servlet-name>spring</servlet-name>
    <servlet-class>
    org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
    <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
    <servlet-name>spring</servlet-name>
    <url-pattern>*.rpc</url-pattern>
    </servlet-mapping>

    </web-app>

  47. David Kuhn Says:

    Hi Christian,

    It’s a bit hard to tell what’s wrong without seeing what your QuoteServiceImpl class looks like. The service context looks okay, my only question is have you got a setter method on the quote service that looks something like setMyObjBO(MyObjectBO bo)?

    Dave.

  48. Cristian Says:

    Hi Dave,

    here’s my QuoteServiceImpl class:

    package com.totsp.sample.client;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Random;

    import com.google.gwt.user.server.rpc.RemoteServiceServlet;
    import com.totsp.sample.bo.IMyObjectBO;

    public class QuoteServiceImpl extends RemoteServiceServlet implements QuoteService {
    private Random randomizer = new Random();
    private static List quotes = new ArrayList();
    private IMyObjectBO myObjBO = null;

    static {
    quotes.add(“No great thing is created suddenly – Epictetus”);
    quotes.add(“Well done is better than well said – Ben Franklin”);
    quotes.add(“No wind favors he who has no destined port – Montaigne”);
    quotes.add(“Sometimes even to live is an act of courage – Seneca”);
    quotes.add(“Know thyself – Socrates”);
    }

    public void setMyObjBO(IMyObjectBO myObjBO) {
    this.myObjBO = myObjBO;
    }

    public String getQuote()
    {
    return quotes.get(randomizer.nextInt(quotes.size()));
    }

    }

    I set a breakpoint on the setter of myObjBO and the getQuote method. On initializing the context I’m getting the breakpoint from the setter for myObjBO been invoked and I see that property been injected with correct value. But, when the getQuote method is been invoked, the myObjBO is null. So somewhere in the middle (I cannot find exactly where ) the spring bean myObjBO is been wipe out (??) and not injected anymore. Is there any process in place that keep active the beans that extends the RemoteServiceServlet while the app is running? Any ideas?

    Thank you,
    Cristian

  49. martin Says:

    Hello,

    is possible to deploy project directly with the help of Eclipse IDE ? Now when i develop some changes on server code, i have to run ant script and then deploy it and then restart tomcat – and thats time-consuming operation. Do you have some tips ? Thank you !

  50. David Kuhn Says:

    Hi Martin,

    The short answer is yes. It is possible to create a GWT project that integrates directly with the Eclipse WTP (Web Tools) features. If you do this then you’ll be able to add your web project to your Tomcat instance in the server view like any other normal web project. I’ve got a couple that work this way at the moment. It’s not exactly straight forward though and requires some knowledge of how to wire up the launch configuration properly.

    I’ll see if I can get some time to write up a tutorial on this, however In the mean time experiment with creating a normal “Dynamic Web Project” and then shoehorning it’s package structure to look like a GWT project. It should include your module file and anything else you’d find in a normal GWT project. You’ll then need to modify the build script I provide in this tutorial slightly to compile the GWT app and copy the contents of the build into the “WebContent” dir. Once that’s done you’ll need to add your project to the server. Once you’ve done that you can create a custom launch configuration that will launch the hosted mode browser using the -noserver flag. Then start up your server, run your custom launch config and you should have a full fledged working GWT debugger which is properly integrated into eclipse. Even better, you can make code changes on the fly and refresh the hosted mode browser and your changes will immediately take effect.

    Good luck mate.

  51. martin Says:

    Thank you ! i will try it soon.

  52. martin Says:

    I created WTP project and copied GWT into it and project runs ! but in browser i see this :

    Failed to get a quote: The call failed on the server; see server log for details

    and in console :

    SEVERE: Exception while dispatching incoming RPC call
    java.lang.RuntimeException: java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
    at org.gwtwidgets.server.spring.GWTRPCServiceExporter.handleExporterProcessingException(GWTRPCServiceExporter.java:344)
    at org.gwtwidgets.server.spring.GWTRPCServiceExporter.processCall(GWTRPCServiceExporter.java:313)

    And thats quite strange…

    Could you give me a hint what could be wrong ? (…or send me your project which already works 🙂 ) Have a nice day. Thanks.

  53. Justin Says:

    Hello,
    Thanks for this article!
    With this system, if I have an hibernate exception for example, can I have say to the user (client-side) that is an hibernate exception and not just “The call failed on the server; see server log for details”?

  54. David Kuhn Says:

    Hi Justin,

    Typically GWT can only move classes that implement IsSerializable across the wire. If you wish to expose an exception you’ll have to wrap it in a custom Exception class that implements IsSerializable for it to be passed across.

    Just as an aside, I wouldn’t normally recommend exposing your users to the type of exceptions that are occurring. It’s bad from a UI design perspective and bad from a security standpoint (knowledge is power to a hacker). If it’s for debugging purposes to make your life easier I’d generally suggest server-side logging as the preferred alternative. That said, I don’t know the context of what you’re trying to do and I’m only making a general recommendation.

    Dave

  55. Sam Loy Says:

    Attn: Fred and David,

    Thank you, David for the article. I’m kinda bummed, cuz I still can’t get it to work. Thank you too, Fred for your contribution.

    Platform: OS-X 10.5; IDE: Intellij JetBrains. GWT: 1.5.3, Java 1.5; deploying on tomcat 6.0.18 using ant.

    Here’s what I’ve done so far:

    1. I implemented it just as you said in the main article, after trying to get it to work for a few hours, I continued reading.
    2. Found the comments about using 1.5 and the changes recommended. Did that. Still no luck.
    3. Saw Fred’s September 24, 2008 at 4:55 pm and started over. I downloaded his code and attempted to deploy (as-is) No luck.

    What I think is going on, is that nocache.js is not getting picked up. The html loads fine, but nothing happens. No compile or deployment errors. I’m hoping you guys can help me out.

    As I said, I am using Fred’s example project as-is, so if you need to peak at the config/src files, just follow the like so kindly provided by Fred.

    I’m sure it is probably some newbi thing, so I’ll keep looking and post the results if I have any success.

    Thanks in advance for your help, and again for your willingness to share your knowledge.

    Sincerely,

    Sam

    Thanks

  56. Sam Loy Says:

    Ahh….sweet success….

    My deployment descriptors were fubar’d.

    Crisis averted! Thanks again, guys!

    Sam

  57. Omar Says:

    Hi Sam,
    What exactly did you do to fix this problem. I am seeing the exact thing. I have been chasing this issue for weeks. I get the following message when I attempt to issue an RPC call from my client. The works in gwt hosted mode:
    Here is the message I get:

    Apr 6, 2009 10:53:16 PM org.apache.catalina.core.ApplicationContext log
    SEVERE: Exception while dispatching incoming RPC call
    java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
    at java.util.ArrayList.RangeCheck(ArrayList.java:547)
    at java.util.ArrayList.get(ArrayList.java:322)

  58. Sam Loy Says:

    Bummer, that’s completely different than the problem I was having.

    Based on the error, I suspect you may have some naming issues. Did you use the source from Fred?

    I suggest using that source, and get it working as-is.

    Sam


  59. […] are already there and work amazingly well, if not quite out-of-the-box. For example, check out Giving GWT a Spring in its Step and […]

  60. kedaar Says:

    This was a really helpful article, thanks!

  61. Prageeth Says:

    When i run my app i get this error

    [WARN] Nested in javax.servlet.ServletException: org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘quoteController’ defined in ServletContext resource [/WEB-INF/Test-servlet.xml]: Error setting property values; nested exception is org.springframework.beans.PropertyBatchUpdateException; nested PropertyAccessExceptions (1) are:
    PropertyAccessException 1: org.springframework.beans.MethodInvocationException: Property ‘remoteService’ threw exception; nested exception is java.lang.NullPointerException:
    org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘quoteController’ defined in ServletContext resource [/WEB-INF/Test-servlet.xml]: Error setting property values; nested exception is org.springframework.beans.PropertyBatchUpdateException; nested PropertyAccessExceptions (1) are:
    PropertyAccessException 1: org.springframework.beans.MethodInvocationException: Property ‘remoteService’ threw exception; nested exception is java.lang.NullPointerException
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1129)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:861)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:421)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:251)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:156)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:248)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:160)
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:733)
    at org.springframework.web.servlet.handler.AbstractUrlHandlerMapping.registerHandler(AbstractUrlHandlerMapping.java:256)
    at org.springframework.web.servlet.handler.SimpleUrlHandlerMapping.registerHandlers(SimpleUrlHandlerMapping.java:125)
    at org.springframework.web.servlet.handler.SimpleUrlHandlerMapping.initApplicationContext(SimpleUrlHandlerMapping.java:103)
    at org.springframework.context.support.ApplicationObjectSupport.setApplicationContext(ApplicationObjectSupport.java:73)
    at org.springframework.context.support.ApplicationContextAwareProcessor.postProcessBeforeInitialization(ApplicationContextAwareProcessor.java:72)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:301)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1167)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:425)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:251)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:156)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:248)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:160)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:287)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:352)
    at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:331)
    at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:265)
    at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:235)
    at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:126)
    at javax.servlet.GenericServlet.init(GenericServlet.java:212)
    at org.mortbay.jetty.servlet.ServletHolder.initServlet(ServletHolder.java:433)

    Here is some of my configurations

    web.xml

    Test

    org.springframework.web.servlet.DispatcherServlet

    1

    Test

    *.rpc

    Test-servlet.xml (Spring beans configurations)

    /**/quote.rpc=quoteController

    GWTSpring.gwt.xml

  62. Prageeth Says:

    My configurations

    web.xml

    Test

    org.springframework.web.servlet.DispatcherServlet

    1

    Test

    *.rpc

    /**/quote.rpc=quoteController


  63. How could you convince somebody who want to use Spring to combine it with GWT? What can GWT do what Spring with its built-in AJAX capability can’t?

    The intention behind this question: I want to use GWT with Spring at work. How could I convince my colleagues?

  64. Paul Martin Says:

    First off, thanks for the great article. It was immensely helpful in setting up Spring + Hibernate + GWT.

    Getting a GWT SerializationException “was not assignable to ‘com.google.gwt.user.client.rpc.IsSerializable’ and did not have a custom field serializer”, complaining about not implement IsSerializable when the GWT documentation clearly states the java.io.Serializable should work?

    GWT isn’t the issue… it’s the controller implementation unfortunately.

    Try modifying the GWTRpcController processCall method to the following:

    @Override
    public String processCall(String payload) throws SerializationException {
    try {
    RPCRequest rpcRequest = RPC.decodeRequest(payload, remoteServiceClass, this);
    onAfterRequestDeserialized(rpcRequest);
    return RPC.invokeAndEncodeResponse(this.remoteService, rpcRequest.getMethod(),
    rpcRequest.getParameters(), rpcRequest.getSerializationPolicy());

    } catch (IncompatibleRemoteServiceException ex) {
    log(“An IncompatibleRemoteServiceException was thrown while processing this call.”, ex);
    return RPC.encodeResponseForFailure(null, ex);
    }
    }

    The issue is that the code does not pass on the security serialization policy (configured by a file generated by GWT with the extension .gwt.rpc). This processCall method fixes that small issue.

    It’s just a copy/paste of the super class (with the same enhancements as outlined by the article), but it fixed the issue for me.

    Cheers

  65. Eric Jablow Says:

    Your example has one logical wart; the QuoteServiceImpl class needs to extend the QuoteService interface and therefore the RemoteService interface in GWT. Therefore, your Spring service classes depend on GWT, even though nothing in them refers to GWT at all. In my work project, the service I am exposing is in another jar file in a project with no knowledge of the UI, and so I want to remove the dependency.

    A coworker wrapped the Spring service in a GWT-aware service, but then one needs to handle transactionality twice. I sought a different solution by trying to use Spring AOP and introductions. However, that failed, because Spring AOP can only add interfaces to classes when there is a specific implementation class for it. However, AspectJ load-time weaving works well. I set up the system for LTW, added a simple aspect class:

    package org.example.gwtwisdom.server;

    @Aspect
    public class QuoteIntroduction{
    @DeclareParents(QuoteServiceImpl.class)
    private QuoteService service;
    }

    and added an aop.xml file invoking this aspect. I could then remove the ‘implements QuoteService’ from the QuoteServiceImpl code, removing the GWT association.

  66. veronica Says:

    Super article, thank you. However I keep getting failed to get a quote error. I am using tomcat 6.0x and build compiles without an error. I changed the gwt path, but nothing changed even when I downloaded the project war. Any suggestions? where should i be looking to solve this problem??

    Cheers,
    Veronica

  67. Leon Says:

    Excellent article. Thanks.

  68. pgtaboada Says:

    Hi,

    using the autowiring bean factory to have the rpc impl autowired is IMHO an easier approach:

    http://pgt.de/2009/07/17/non-invasive-gwt-and-spring-integration-reloaded/

  69. rajneesh bhandari Says:

    Great work .

    Very clear and to the point

    Cheers
    Rajneesh

  70. H Elrufaie Says:

    im facing the same problem reported previously by ” Sam Loy Says April 7, 2009 at 3:24 am “.

    that is, i invoke the “http://localhost:8080/GwtWisdom/GwtWisdom.html” servlet but nothing happens after that. no errors or exceptions in the logs.

  71. nazica Says:

    I have the same problem like Cristian has. The problem is double instantiation of RemoteService. First instantiation I have from Spring IoC but the second instantiation – from GWT (my suggestion). Spring, of course, does correct initialization, but GWT doesn’t create any parameter injection.
    So, GwtRpcController doesn’t invoked when I do RPC request to a server.
    Any suggestions?

  72. nazica Says:

    Ok, all works fine now!
    The problem – my incorrect URL mapping in web.xml.
    Thanks again, David


  73. quiza sabes, pero tu pagina se ve raro en Safari en un Mac.,

  74. valery Says:

    Hello,
    When I try to run ant I have this error :
    javax.servlet does not exist

    When I try to run hosted mode I have this one :
    [ERROR] Not compatible with HttpServlet: biz.manex.chbah.crc.web.server.CRCServiceImpl (does your service extend RemoteServiceServlet?)

    [ERROR] Unable to dispatch request

  75. dma Says:

    Great article, althought i takes a while to understand if you get it from scratch.

    Best regards


  76. […] всякие инструменты. Сейчас иду шаг за шагом по мануалу с поправкой на то, что версия давно уже не 1.5 а 2.0, и […]

  77. Arun Says:

    Very nice artcile. it helped me a lot

  78. Vinod Says:

    Now that we have GWT 2 and Spring 3, has anyone tried this lately?

  79. Kirti Says:

    This integration works and helped me a lot but after integration this.getThreadLocalRequest() method invocation in my serviceImpl class returns null. Please help

  80. shan Says:

    Hi ..
    Great article..I see a lot of people here have got prob with the execution of the code given… specially the “Failed to get a quote” issue, has any one come out with a solution for this.. I am using tomcat 6.0.10 so the version should not be the issue.. If any one had cracked this please reply..

  81. jay | “Failed to get a quote” Says:

    >> “Failed to get a quote”

    I managed to get it working with Spring 3.x & GWT 2.x. & Tomcat 6.0.26. The example still works great and made me save a lot of time and hassle, now I’m up to getting a MAVEN build for the project.

    To overcome the :
    “Not compatible with HttpSevlet: org.example.gwtwisdom.server.QuoteServiceImpl (does your service extend RemoteServiceServlet?) Unable to dispath request” (you’ll see this in the Tomcat log). In the browser: “Failed to get a quote” . I did what Tomcat asked:

    public class QuoteServiceImpl extends RemoteServiceServlet implements QuoteService
    {
    ….
    }

    i.e. extend the RemoteServiceServlet and voilà! Everything is running smoothly.

  82. Deepak Singh Says:

    Really a nice explanation. This had helped me a lot in understanding the approach in integrating spring & gwt. Probably similar approaches are followed in GWT-SL libraries, and now they (GWT-SL) have some advanced one too.

  83. Namit Karlekar Says:

    Thanks a bunch.. This helped me out a lot..

  84. Jeff Says:

    Incredibly helpful. I didn’t — at all — expect it to compile and run smoothly when but (minus one typo), it ran flawlessly.

    I looked around for a “Donate” button on your page but couldn’t find anything. Any way to buy you a PayPal beer?


  85. […] giving-gwt-a-spring-in-its-step […]

  86. Chicagoan Says:

    A gift that keeps giving! Thanks bro, this was very helpful!


  87. I never thought of it that way, well put!

  88. kapustmaks Says:

    Всем Привет! Кто знает где находится село дебесы?.

  89. vinu Says:

    Hi

    Thanks a lot for this example,which helps me alot..have a click on the spring-gwt integration..

  90. Parvinder Kumar Says:

    Thanks a lot guys…My head was running hot for last three days..It did work now…Let me know if any of you facing some issue at parry.ism@gmail.com

  91. ashish Says:

    that was pretty cool?Did anyone use maven for build instead any lucks i am gonna try out maven and see if i meet the success.

  92. Harvey Says:

    Thanks a lot for that. Apparently the source code link is broken, where can I get it?

  93. Dave Kuhn Says:

    Looks like you’re right Harvey, Mediafire seem to have ditched all my files. Shame, it’s so long ago now that I no longer have the code.

    Things have come a long way with Spring and GWT since I first wrote this article. I’d suggest perhaps checking out Spring Roo’s GWT integration and some more modern approaches to doing this using Aspects and Annotations these days.

    -Dave

  94. rix Says:

    thank you so much for a very nice articale


  95. . .
    - , - ,
    , :
    . , .
    XXI .
    , , ,
    .
    . , ,
    - , ... , , . , , - . , : , , , , . , . .
    , .
    , ,
    . ,
    .

  96. spring-user Says:

    Is possible to do the same with annotated (@Controller annotation) Controller that can have more mapped to it path (RESTful) ?

  97. Dave Kuhn Says:

    I don’t see why you couldn’t. It’s been a while since I’ve written anything with Spring though and I haven’t tried that approach.

    Let me know what you discover!

  98. marioosh Says:

    Thanks for that article. Very good approach.

    Thank to Paul Martin for Your patch to GWTRpcController 🙂 Now i have working GWT (2.4) + Spring + Hibernate app.

    You can clone my working skeleton app from: https://github.com/marioosh-net/GWT/tree/master/gwt-spring


  99. […] are links to some resources – https://technophiliac.wordpress.com/2008/08/24/giving-gwt-a-spring-in-its-step/ and Experiences with integrating spring 3 mvc with GWT? . Tagged: GWTJavaquestionsspring […]

  100. kuar Says:

    dg


  101. Sir ur tutorial really helped me alot. thank u so much for this wonderful n simple easy to understand tutorial.
    though i have doubt in the flow of the application.;….well as we deploy it on server,i suppose web.xml gets called n then -servlet.xml one… i ‘m not understanding when is gwt.xml is getting called? is it called along with web.xml??
    i would be thankful if u can explain me the control in the application
    thank u.

  102. Senaida Says:

    I love your blog.. very nice colors & theme.
    Did you design this website yourself or did you hire someone to do it for you?
    Plz reply as I’m looking to construct my own blog and would like to know where u got this from. thank you

  103. Dave Kuhn Says:

    Thanks, it’s just one of the standard wordpress themes.

  104. saji Says:

    Thankyou very much sir. You saved my day

  105. Aleksey Says:

    Thanks for the tutuorial. Very interesting reading.

    One note. Why don’t you make RemoteServiceServlet as a field of the controller? You use RemoteServiceServlet(remoteService) . So you don’t need to override method because RemoteServiceServlet will use service that you passed to it in the constructor.

    It would be then simple like that:

    public class GwtRpcController implements
    Controller, ServletContextAware {

    private ServletContext servletContext;

    RemoteServiceServlet delegateServlet;

    public ModelAndView handleRequest(HttpServletRequest request,
    HttpServletResponse response) throws Exception {
    delegateServlet.doPost(request, response);
    return null;
    }

    @Override
    public ServletContext getServletContext() {
    return servletContext;
    }

    public void setServletContext(ServletContext servletContext) {
    this.servletContext = servletContext;
    }

    public void setRemoteService(RemoteService remoteService) {
    this.remoteService = remoteService;
    this.remoteServiceClass = this.remoteService.getClass();
    }

    }

  106. Aleksey Says:

    Forgot about setRemoteService():

    public void setRemoteService(RemoteService remoteService) {
    this.delegateServlet = new RemoteServiceServlet(remoteService);
    }

  107. Dave Kuhn Says:

    Thanks Aleksey. Have you tested this code, does it work?

    It’s been so long since I wrote this that I can hardly recall why I implemented it the way I did. Something tells me you’re still going to need to override RemoteServiceServlet.processCall in order to delegate to the injected service. Has something changed in recent versions of GWT that means this is no longer necessary?

  108. Aleksey Says:

    Hi Dave. Thanks for the reply.

    No, I did not test this. That is my guess which I made by looking at GWT source code. It must be that the overloaded constructor appeared in the new version of the library.


  109. […] using GWT (2.4) with Spring integrated as in this article. I have problem with getting list of User from database (Hibernate) and populate DataGrid with it. […]


  110. Excellent writeup! I’ve applied it, and am pleased with the results.

    I may not be obvious to some that in order for GWT remote logging to work, you will have to create and use an implementation of RemoteLoggingService which does not extend RemoteServiceServlet.


  111. […] used by GWT and instead create your own Spring controller to handle incoming GWT-RPC requests. This blog post was the key to integrating the two […]


  112. […] usando GWT (2.4) con Molla integrata come in questo articolo. Ho un problema con ottenere l’elenco di Utente dal database (Hibernate) e popolare DataGrid. […]


  113. […] 我想知道如何将Spring与GWT集成。是否需要像this post中那样实现GWT控制器?如果是这样,此控制器和我现有的控制器是否应该放在单独的模块中? […]


Leave a comment