Platinum Solutions Corporate Website


Plumbing your exceptions thru RPC in GWT

You've got a great GWT web-client application but you can't figure out why all your custom, server-side exceptions are rolling into your client app as anything but your custom exception. Yes, GWT supports custom exceptions as valid 'failure' responses back to your GWT client, but when they get to your handler all you see is IvocationTargetException: see server log." If you've done some research you may end up with: "Service method com.my.private.company.project.rpc.service.Classname.processLogin(java.lang.String) threw an unexpected exception: Invalid username / password." Dangit Scotty! Nothing like the friendly message bundled in your custom exception you were expecting to see. At the moment, plumbing is more like plunging!

Have no fear, GWT documentation aside (which is pretty good (except for exceptions :D )), here's some simple tips to patch/unclog that RPC channel.

First, GWT treats all java.lang.RuntimeExceptions the same: the client is informed of an InvocationTargetException with a message of 'see server log'. This isn't altogether bad: RuntimeExceptions should not occur at production - that's what testing is for, and any java.lang.Errors should bring things to a hault anyway. This leaves us with everyone's favorite, checked exceptions.

Your server-side RPC interface needs to be throwing checked exceptions, more specifically a subclass of com.google.gwt.user.client.rpc.SerializableException. Alternatively, you could subclass java.lang.Exception and implement IsSerializable but there are a few other behind-the-scenes tricks you'd be missing performed by GWT's SerializableException. Also, SerializableException does not support exception chaining because revealing stack traces to the client is an obvious security risk (snooped or not).

Second, GWT's RPC encoding and processing logic (for HTTP response assembly) examines your interface's declared exceptions: if your invoked RPC method has encountered an exception not declared in the throws clause of your RPC interface method, GWT makes a fleeting mental note of your undeclared exception as an UnexpectedException (instead) and throws that to the client, with your message intact with some invocation method signatures included in the message. So by all means - declare every exception you'll be throwing from your server.

Next, remember your cluster of classes surrounding the marshalling of GWT activity through your RPC interface? Your <my_rpc_interface>Async interface normally needs to be a mirror image of your <my_rpc_interface> interface with the additional parameter of an AsyncCallback reference on each method. In this case, while you'll need to declare your checked IsSerializable exceptions in your <my_rpc_interface> methods, do not declare them in your <my_rpc_interface>Async methods. GWT's client RPC marshalling already processes exceptions and redirects to the appropriate onFailure(..) method of your AsyncCallback objects. If you did, you'd need to strangely catch exceptions from all of your RPC method calls in the client (making an even bigger mess of your client code) which would never catch an exception anyway (like I said, they're redirected to your onFailure methods).

As a recommendation, judiciously throw SerializableException exceptions in your server-side code. Best practice suggests that you specialize (subclass) the common exception for as many occassions as you have a need for a unique checked exception. This may make a mess of your server-side method signatures (particularly if your design has deep stacks from RPC calls to the last checked exception in the stack) so alternatively, throw subclassed, custom java.lang.RuntimeExceptions, catch these subclasses in your RPC implementation servlet, and re-throw as subclasses of SerializableException. GWT will let these carry on their merry way, with unadulterated messages to your client.

What you should end up with is a simple, clean, friendly 'Invalid username / password' message (if your onFailure method simply displays the message from the Throwable argument) that you can go decorate how you like in the client.

If this post didn't help you because you're seeing some other kind of exception, well, GWT's RPC marshalling logic gives several different messages depending on the problem. I would suggest you check your server log as it probably will relate to an incomplete/unstable connection in the RPC interface.

~ dan

Comments

Anonymous (not verified) Wed, 1969-12-31 19:00

Google has a tutorial for this:

http://code.google.com/webtoolkit/doc/latest/tutorial/RPC.html#exceptions

Anonymous (not verified) Wed, 1969-12-31 19:00

can you please add some code snippets and/or a small codesample application?

Alex (not verified) Wed, 1969-12-31 19:00

I read this article while trying to understand some undocumented cases in GWT RPC exception handling. While the article does elaborate on the subject, a couple of things are inaccurate:

1. UnexpectedException can't be thrown to the client. You see, this class is located in package com.google.gwt.user.server.rpc, and including catch(UnexpectedException ex) in client code results in a a compilation error.

2. The statement "First, GWT treats all java.lang.RuntimeExceptions the same: the client is informed of an InvocationTargetException..." conflicts with "...if your invoked RPC method has encountered an exception not declared in the throws clause of your RPC interface method, GWT makes a fleeting mental note of your undeclared exception as an UnexpectedException...". There is no mentioning of IncompatibleRemoteServiceException.

3. IncocationTargetException is actually called InvocationException.

Overall, thanks for the attempt to clarify GWT exception handling but a better and more elegant explanation is needed.

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Lines and paragraphs break automatically.

More information about formatting options