GWT is quite evolving recently. There are a couple of reasons for that:


- Coding apps like Gmail and Google Wave
We all appreciate the speed of the Gmail UI. It's just like operating on a local client. Moreover the coming (already popular) Google Wave has been build using GWT.
- Cross-browser compatibility
The produced outcome by GWT is pure JavaScript, optimized for performance and cross-browser compatibility. The major advantage: there is no need for installing a runtime, plugin or whatever. It's just plain JavaScript!
- IDE support and Hosting solutions
The new Google Plugin for Eclipse makes it easy to develop GWT apps. Debugging, hosted mode browsing without the need of a deployment makes it feel like developing desktop clients.
Moreover a 1-click deploy to Appengine is provided which can be used as the hosting solution with Google-like DB already integrated.
For making this enterprise ready however you probably would like to use some more powerful tools especially at the server-side. You know
Spring :) ? If not, you should get in contact with it.
What I tried to do is to integrate GWT with Spring and Google Appengine. I tried to do that already about 2 years ago and succeeded but unfortunately I didn't have the time to continue. Meanwhile GWT has evolved and there is a lot of support available on the web and even on the GWT Googlecode hosting for integrating both (just google for it).
The central element for connecting both is to have the
GWTController which accepts the incoming HTTP requests, decodes the Google-RPC payload and invokes the correct implementation of the server-side service, catches the response, encodes everything and sends it back.
So I configured the standard GreetingService demo and launched my GWT app and see there..
WARNING: Nested in org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.NullPointerException:
java.lang.NullPointerException
at javax.servlet.GenericServlet.getServletContext(GenericServlet.java:163)
at com.google.gwt.user.server.rpc.RemoteServiceServlet.doUnexpectedFailure(RemoteServiceServlet.java:284)
at com.google.gwt.user.server.rpc.RemoteServiceServlet.doPost(RemoteServiceServlet.java:99)
at com.myapp.demo.server.GWTController.handleRequest(GWTController.java:51)
at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:48)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:781)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:726)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:636)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:556)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:713)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:806)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1093)
at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
at com.google.appengine.tools.development.StaticFileFilter.doFilter(StaticFileFilter.java:121)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
A nice NullPointerException when the "javax.servlet.GenericServlet.getServletContext()" gets invoked. Perfekt, was not even my code. I searched a while for a solution, when some hints on the web lead me into the right direction. For avoiding this problem the GWTController has to be made "context aware". Basically it has to get the ServletContext injected. By doing so, the GWTController code should look like this:
public class GWTController extends RemoteServiceServlet implements Controller, ServletContextAware {
// Instance fields
private RemoteService remoteService;
private Class remoteServiceClass;
private ServletContext servletContext;
// Public methods
/**
* Implements Spring Controller interface method.
*
* Call GWT's RemoteService doPost() method and return null.
*
* @param request
* current HTTP request
* @param response
* current HTTP response
* @return a ModelAndView to render, or null if handled directly
* @throws Exception
* in case of errors
*/
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
doPost(request, response);
return null; // response handled by GWT RPC over XmlHttpRequest
}
/**
* Process the RPC request encoded into the payload string and return a
* string that encodes either the method return or an exception thrown by
* it.
*/
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 e) {
return RPC.encodeResponseForFailure(null, e);
}
}
/**
* Setter for Spring injection of the GWT RemoteService object.
*
* @param RemoteService
* the GWT RemoteService implementation that will be delegated to
* by the {@code GWTController}.
*/
public void setRemoteService(RemoteService remoteService) {
this.remoteService = remoteService;
this.remoteServiceClass = this.remoteService.getClass();
}
@Override
public ServletContext getServletContext() {
return servletContext;
}
public void setServletContext(ServletContext servletContext) {
this.servletContext = servletContext;
}
}
In this way the ServletContext gets fetched from here. Note, if your service implementations classes do also need to use the ServletContext, you have to basically do the same thing: implementing the ServletContextAware interface and overriding the corresponding methods. Then you should be done and everything should just work seamlessly :) Just comment if you have any questions about it.
Questions? Thoughts? Hit me up
on Twitter