Improved ExceptionHandling with GWT RequestFactory

by Stefan

Server Side Exceptions

The default setting for handling exceptions in the server is not optimal. An exception on the server-side is caught and handled by the class DefaultExceptionHandler. Only the exception message is transferred to the client but nothing is logged. As this happens inside an http 200 response, the web app container doesn’t notice that something went wrong. The default behavior can be changed by replacing the DefaultExceptionHandler during the initialization of the RequestFactory servlet.

Therefore, a custom servlet that extends from the default RequestFactoryServlet needs to be defined to pass a custom exception handler in the constructor.

package cleancodematters.server;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.web.bindery.requestfactory.server.ExceptionHandler;
import com.google.web.bindery.requestfactory.server.RequestFactoryServlet;
import com.google.web.bindery.requestfactory.shared.ServerFailure;

public class CustomRequestFactoryServlet extends RequestFactoryServlet {

  static class LoquaciousExceptionHandler implements ExceptionHandler {
    private static final Logger LOG = LoggerFactory.getLogger( LoquaciousExceptionHandler.class );

    @Override
    public ServerFailure createServerFailure( Throwable throwable ) {
      LOG.error( "Server error", throwable );
      return new ServerFailure( throwable.getMessage(), throwable.getClass().getName(), null, true );
    }
  }

  public CustomRequestFactoryServlet() {
    super( new LoquaciousExceptionHandler() );
  }
}

The 2nd parameter of ServerFailure denotes the exception type. Optionally, the exception stacktrace can be passed as 3rd parameter. However, this inflates the http response and displaying a stacktrace to an end-user is questionable.
Finally, make sure to register the custom servlet in the web.xml:

  <servlet>
    <servlet-name>gwtServlet</servlet-name>
    <servlet-class>cleancodematters.server.CustomRequestFactoryServlet</servlet-class>
  </servlet>
  
  <servlet-mapping>
    <servlet-name>gwtServlet</servlet-name>
    <url-pattern>/gwtRequest</url-pattern>
  </servlet-mapping>

The Client Side

When firing a request, clients usually pass a subclass of Receiver. The default implementation raises a RuntimeException containing the message from ServerFailure if the fatal-flag is set to true. If running in dev mode this exception is written to the development mode console, in production mode this causes a JS error.
To change this, one could either provide a customized receiver class from which all receivers extend. Alternatively, a generic exception handler can be registered using GWT#setUncaughtExceptionHandler().

You might also have noticed, that in most cases, a UmbrellaException is thrown which wraps the RuntimeException. Here’s a customized exception handler that extracts the original exception and displays the message to the user.

package cleancodematters.client;

import com.google.gwt.core.client.GWT.UncaughtExceptionHandler;
import com.google.gwt.user.client.Window;
import com.google.web.bindery.event.shared.UmbrellaException;

public class CustomUncaughtExceptionHandler implements UncaughtExceptionHandler {

  @Override
  public void onUncaughtException( Throwable e ) {
    // Get rid of UmbrellaException
    Throwable exceptionToDisplay = getExceptionToDisplay( e );
    // Replace with your favorite message dialog, e.g. GXT's MessageBox
    Window.alert( exceptionToDisplay.getMessage() );
  }

  private static Throwable getExceptionToDisplay( Throwable throwable ) {
    Throwable result = throwable;
    if (throwable instanceof UmbrellaException && ((UmbrellaException) throwable).getCauses().size() == 1) {
      result = ((UmbrellaException) throwable).getCauses().iterator().next();
    }
    return result;
  }
}

(To not bother your users with empty dialog boxes you should also check for NullPointerExceptions whose message is usually empty.)

A custom exception handler needs to be registered once, e.g. in your application’s entry point by calling

        GWT.setUncaughtExceptionHandler( new CustomUncaughtExceptionHandler() );
About these ads

15 Responses to “Improved ExceptionHandling with GWT RequestFactory”

  1. Awesome! Works like a charm.

  2. Bei mir funktioniert es nicht :( Statt der Fehlermeldung erscheint nur der Text “[[[D”.
    Ist das Problem schon vorgekommen und wissen sie, wie man es löst?
    Ich habe den Code quasi nur rüberkopiert, weiss also nicht wo der Fehler liegt.
    Da die Exceptions nicht richtig angezeigt werden, kann ich auch so meinen Programmfehler nicht korrigieren :(
    Könnten Sie mir diesbzgl. eine E-Mail senden (sollte ja hier angezeigt werden) und weiter helfen, ich wäre Ihnen sehr dankbar!

  3. Hello,
    first I want to thanks you for these superb articles on GWT RequestFactory, they really helped me getting started quickly.
    I’m trying to reuse this article to improve error handling, it is working ok for the server side, but the client side recipe does not work out of the box for me.
    The ServerFailure is never handled correctly by the Receiver.
    Did you tested this against GWT 2.4 already ?
    I spotted some small differencies in gwt AbstractRequestContext between 2.3 and 2.4. maybe something changed.

  4. Very helpful!! Thanks Stefan!!

  5. This is my take. It also includes the stacktrace:

    public class CustomRequestFactoryServlet extends RequestFactoryServlet {

    private static final long serialVersionUID = 5487386564879226718L;

    static class CustomRequestFactoryServletExceptionHandler implements ExceptionHandler {
    private static final Logger LOG = LoggerFactory.getLogger(CustomRequestFactoryServletExceptionHandler.class);

    @Override
    public ServerFailure createServerFailure(Throwable throwable) {
    LOG.error(“Server error”, throwable);
    return new ServerFailure(throwable.getMessage(), throwable.getClass().getName(), getStackTraceAsString(throwable), true);
    }

    private String getStackTraceAsString(Throwable t) {

    StringBuffer sb = new StringBuffer();

    for (StackTraceElement elem : t.getStackTrace()) {
    String stackTraceLine = “at ” + elem.getClassName() + “.”
    + elem.getMethodName() + “(” + elem.getFileName() + “:” + elem.getLineNumber() + “)\n”;
    sb.append(stackTraceLine);
    }

    return sb.toString();
    }

    }

  6. hi
    is there any example of creating grid with GWT RequestFactory

  7. Hi, I tried the above but my onFailure never get’s called. It seems to always return success even when an exception is thrown. Any idea why that would be? http://stackoverflow.com/questions/12710983/request-factory-serverfailure-not-seen-by-client

  8. i tried your solution It always return success except for validation exceptions!
    I tried with unique constraint on an entity on server side i get the exception as expected but not on client on failure is never called can anybody help me?thank you for your attention.

  9. Hi Stefan, thanks for this post.

    One question if I may.

    I am using GIN on my client and I have trouble getting my UncaughtExceptionHandler registered. I do GWT.setUncaughtExceptionHandler( new CustomUncaughtExceptionHandler() ); on my entry point module’s configure() call (which should be my application entry point) but it does not work, the handler does not get registered and I still have “Uncaught exception escaped”

    Any ideas why?

Trackbacks

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 25 other followers

%d bloggers like this: