Skip to content →

GWT’s AsyncCallback and Promises

One of the many ways GWT uses to call backend methods in the frontend is through its RPC service implementation. To use the RPC service one has to code three separate code entities.

The backend:

The frontend:

The asynchronous interface:

Using the code entities defined above, looks something like this:

This code simply binds a backend method to a frontend interface method and dispatches a call to the backend. Once the call completes and the result is available, the onSuccess method is called. An onFailure is also required to be implemented but we’re omitting it here for simplicity. Nothing new here. This is simply a callback passed to process the data, like it has been done multiple times before in JavaScript frontends (eg $.ajax).

Callbacks though have a set of drawbacks when designing software. First of all, they are not composable. If one needs to perform a couple of asynchronous steps in sequence, pretty soon he ends up with callbacks inside callbacks inside callbacks, also known as callback hell. It’s very easy to lose control of the application flow under such a scenario.

Promises on the other hand offer great composability and readability when used in the code. Using promises instead of callbacks helps organize your asynchronous operations in logical units and clearly indicate an execution path that can support both parallel and sequential operations. Sadly, GWT does not support promises by default and sometimes, rewritting the whole communication layer using another type of mechanism (e.g. request builder) is not a viable solution. What we’re going to build in this article, is a wrapping system around an existing rpc service that will allow us to execute methods and get promises as a result, completely forgetting AsyncCallback’s existence.

The first problem we are faced with is the nature of GWT’s RPC system. By default and without the ability to change it, GWT requires each method to provide an implementation of the AsyncCallback interface. What we want to do instead, is avoid writting the callback implementation and instead get back a Future where we can chain our onSuccess and onFailure methods. In other ways we need code that will generate two things: An AsyncCallback implementation that we will pass to the RPC and a Promise/Future that we are going to use for our application logic. In functional terms, that would be a tupple. So throwing in a bit of Javaslang, we could create a method as follows:

To put it simple, we created a Promise and an AsyncCallback that receives the promise and calls its failure and success method corresponding to it’s own success and failure scenarios. Eventually we couple those two into a Tuple and return them. Now, we can wrap our getCars method with another method that will encapsulate the  call and the handling of the Tuple.

This new getCars is improved over the old one for two reasons. One, we don’t have to implement the callback ourselves anymore whenever we call the method. Two, we now have a Future type returned and we can work on it without writting code inside the anonymous class of AsyncCallback. Here’s an example on how that could be used.

While that’s a great step towards writting better and much simpler asynchronous code, there’s still something that doesnt feel so perfect. That is, for every RPC service method already implemented in the application, we have to writte a wrapper method. If we had a big RIA application with dozens of RPC calls we’d have to create a wrapper for each one of them. What is more, we’ve now introduced an extra layer of complexity in our software. For each new backend call needed, we have to write both the RPC service method (actually that would be three methods) and the wrapper method that will return us the futrue.

To avoid all that hussle, intuitivelly we want to supply the RPC method to some code that will automatically consume a callback in the method and return the Future. That soulds like … a Java 8 consumer interface. Coding one such method could look like this:

Now we just have to provide a consumer with the method of the RPC service we just wanna call, as seen at the example code that follows.

Published in Software Development

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *