While developing GWT Remote Procedure Calls(RPC), many of you have experienced the limitations of the default GWT exception handling model. I will demonstrate this with a sample application. If you create the default GWT hello world application you will notice three RPC service classes being created for you:


interface GreetingServiceAsync {
   void greetServer(String input, AsyncCallback<String> callback)
          throws IllegalArgumentException;
}

@RemoteServiceRelativePath("greet")
interface GreetingService extends RemoteService {
   String greetServer(String name) throws IllegalArgumentException;
}

class GreetingServiceImpl extends RemoteServiceServlet
                 implements GreetingService {
   public String greetServer(String input) throws IllegalArgumentException {
      { // let's just throw an error for demonstration
         throw new IllegalArgumentException ("Bad arguments passed");
      }
   }
}

So, the error handling works this way. GreetingServiceImpl captures an error and throws a runtime failure, in our case IllegalArgumentException. So far so good. But, what if we need to throw a different error. Let’s say MyIllegalArgumentException? Well by design (GWT design), we need to declare it on each three RPC methods:


interface GreetingServiceAsync {
   void greetServer(String input, AsyncCallback<String> callback)
            throws MyIllegalArgumentException;
}

@RemoteServiceRelativePath("greet")
interface GreetingService extends RemoteService {
   String greetServer(String name) throws MyIllegalArgumentException;
}

class GreetingServiceImpl extends RemoteServiceServlet
                 implements GreetingService {
   public String greetServer(String input) throws MyIllegalArgumentException{
      { // let's just throw an error for demonstration
         throw new MyIllegalArgumentException("Bad arguments passed");
      }
   }
}

Which is not fun. It’s quite cumbersome. You need to declare the exception on each RPC method in 3 places – the Service, ServiceAsync and ServiceImp classes. To make the matter even worse as long as you have multiple methods and variety of exception types you end up into the “exception over-declaring hell” with methods looking this way myMethod() throws Exception1, Exception2, Exception3, Exception4 (and don’t forget, you need to declare this in three places – 3 RPC classes).

Being curious (and lazy) you may wonder what will happen if:

A. We simply skip declaring the errors from the method signature:
/* no exception being declared*/
greetServer(String input, AsyncCallback<String> callback)
B. Or derive and throw a business failure from the declared Exception. We create a derived exception from IllegalArgumentException and the method throws the child error, while the method signature has the parent one:

class AnotherBusinessException extends IllegalArgumentException {
   ..
}
class GreetingServiceImpl extends RemoteServiceServlet
                 implements GreetingService {
   public String greetServer(String input) throws IllegalArgumentException{
      { // let's just throw an error for demonstration
         throw new AnotherBusinessException("Bad arguments passed");
      }
   }
Testing those cases against GWT RPC results with:
  • A.   HTTP/1.1 500 Internal Error
    [WARN] Exception while dispatching incoming RPC call com.google.gwt.user.server.rpc.UnexpectedException: Service method ‘public abstract java.lang.String GreetingService.greetServer(java.lang.String)’ threw an unexpected exception: java.lang.IllegalArgumentException..
  • B.    HTTP/1.1 500 Internal Error
    [WARN] Exception while dispatching incoming RPC call com.google.gwt.user.client.rpc.SerializationException: Type ‘org.roussev.hello.client.AnotherBusinessException’ was not included in the set of types which can be serialized by this SerializationPolicy or its Class object could not be loaded. For security purposes, this type will not be serialized…
Which is not very promising. GWT doesn’t like it and spit us with 500 Server Errors. In case A, GWT the exception type was not recognized defaulting to UnexpectedException. In case B. GWT kinda liked the type, but refused to load it for security purposes. Go figure..

All said, GWT exception handling forces us to declare all those business errors as part of the method signatures in all three RPC classes. And this is a tedious, error prone and repetitive process. Instead we (the lazy developers) are looking for more dynamic approach. We are looking for an approach where:

  1. An RPC Service method should not have to declare any runtime business failures.
  2. The server should handle the runtime business failures gracefully with 200 OK, instead of 500 Error
  3. And lastly, UI should receive the exact error type (not some gwt StatusCodeException or an UnexpectedException) directly into the consuming callback void onFailure(Throwable e).
Next post is GWT Dynamic Exception Handling overcoming GWT exception limitations.