Play Framework – Adapting Java 8 CompletableFutures to Play F.Promises

Recently, I have been playing around with Java 8 and the Play Framework (2.4RC1) – bad pun intended :P. As I worked to develop the codebase, I found the need to integrate with Java 8 CompletableFuture‘s. No big deal, right?

At first, it didn’t seem to be, but as I continued coding, I quickly became very unhappy with how my code was turning out. The Play Framework for Java introduces some classes to handle promises. The Play p.l.F.Promises and p.l.F.RedeemablePromises. These classes essentially solve the same problem as j.u.c.Future, j.u.c.CompletableFuture. Intermixing such similar constructs within the same code base quickly create a bad code smell. Ultimately, I made a decision… All async code will be written using Java’s j.u.c.Future/CompletableFuture and not with Play p.l.F.Promise/RedeemablePromise.

Why? Two reasons:
1. Code reuse.

  • j.u.c.Future and j.u.c.CompletableFuture are part of Java 8 and thus ubiquitous
  • F.Promise only exists within the Play Framework.
  • Using pure Java constructs means more flexibility and compatibility with other frameworks.
  • Gossip: Play Framework 3.0 for Java may drop Promises for Java Futures.

2. ReactiveX – Reactive Extensions

  • Rx Observables work seamlessly with j.u.c.Future and j.u.c.CompletableFuture
  • (Yes, I also plan to use Rx)

Those familiar with Play Java are likely puzzled. As you know, I cannot possible guarantee all async code is written with Java’s j.u.c.Future/CompletableFuture. Afterall, there are a number of Play Framework APIs that requirep.l.F.Promise. So what do we do?

Fortunately, the solution is relatively simple. We adapt!
At this point, I must give credit to matiwinnetou. His RxPlay adapter is the primary inspiration for this solution.

Previously, we noted that Play’s p.l.F.Promises and p.l.F.RedeemablePromises, essentially solve the same problem as j.u.c.Future, j.u.c.CompletableFuture. The semantics between the two constructs are very similar, thus implementing an adapter can be done very easily and quite efficiently.

Below is the code, RxFuture that does just that!

It simply takes as input a j.u.c.CompletableFuture, then constructs a p.l.F.RedeemablePromise. The Promise is completed asynchronously, when the Future completes. As you can see, we are able to do this very efficiently and with very little code — and most importantly, we still able to maintain asynchronicity!

[code language=”Java”]

package com.dimascio.play;

import play.libs.F;

import java.util.concurrent.CompletableFuture;

public class RxFuture<T> {

private final CompletableFuture<T> cf;

public RxFuture(final CompletableFuture<T> cf) {
this.cf = cf;
}

public static <E> F.Promise<E> toPromise(final CompletableFuture<E> obs) {
return new RxFuture(obs).adopt();
}

public F.Promise<T> adopt() {
F.RedeemablePromise<T> rPromise = F.RedeemablePromise.empty();
cf.whenCompleteAsync((res, err) -> {
if (err != null) {
rPromise.failure(err);
} else {
rPromise.success(res);
}
});
return rPromise;
}
}

[/code]

You can find the gist on Github.

Thanks!

You may also like...

1 Response

  1. What about the other direction, getting a Promise from play and returning a CompletableFuture?