Sunday, April 17, 2016

Spring Async and Java's 8 CompletableFuture, a small change to the existing tutorial #spring #async #java8

It is known that I am not the biggest fan of Spring, but at the time being I work for an organization that maintains too many projects utilizing Spring (in different forms and versions). I still remain skeptic towards Spring, of course there are some very nice ideas, there are some nice (too many) abstractions, there are some very handy 'shortcuts' to bootstrap complex projects. I am not going to elaborate on the things I don't like in this post.

One thing I like on Spring's documentation, is their getting started guides. Well written and concrete. I was reading through, a short guide, for 'Async' method execution, through SpringBoot /RestApi [link] .

So this is this the implementation of the example 'asynchronous' findUser() method. Full source here.

public Future<User> findUser(String user) throws InterruptedException {
  System.out.println("Looking up " + user);
  User results = restTemplate.getForObject("" + user, User.class);
  // Artificial delay of 1s for demonstration purposes
  return new AsyncResult<User>(results);

I was wondering why there is still a 'Future' in the example, while we have been introduced Java8, CompletableFuture. I guess the original authors want to preserve backwards compatibility with previous versions of Java (6 / 7 ) - where this construct is not available.

It seems that someone else had the same question, and wrote a very nice example here. In one of the comments, you can see a hint that from version 4.2 and onward the Spring API, would be compatible with the use of CompletableFuture, on top of Future & AsyncResult which are already provided. I thought, `well it's a shame, why not try it or even document it, because if someone lands on this example, he/she might stay with the current implementation` - why not use something standard?. 

So I decided to make a tiny change, remove Future and replace it with CompletableFuture, also comment out the calls to Future.isDone() and replace it with the very handy CompletableFuture.allof() method.

So I changed the return type on the 'service' method

while, updating the, caller code - to sync on all 3 futures and once allof() them were done, we could print the results.

The modified, example can be found here. I found this and this blog posts from Tomasz Nirkewicz, a very nice and pragmatic walk through of CompletableFuture, rich method list. There is also a quite complete presentation by my favorite Devoxx Speaker , Jose Paumard you can find it here.



  1. great post, thanks :)

  2. what if findUser throw Exception? Cf wont complete exceptionally, also using sleep in asyn is bad pattern

    1. Hi, the code above is a very simple example. Of course you would never use sleep.

      Now when it comes to exceptions - you would need to catch the exception and then create a new CompletableFuture and use the `` method