Using vavr with Play Framework

Introduction

This topic aims to describe our experience working with vavr + play. I am interested in know other experiences (problems and how you solved it) or what do you think about this combination.

What is vavr

Vavr is a library for functional programming in Java. It is high influenced by Scala and implements some interesting packages: Collections, it mean Lists, Maps, Sets, Tuple, etc. Some monads, it mean Try, Option, Either, Future, etc. And another useful api like For, Match etc.

Why is it interesting

In our case, we have three years of experience working with Scala in some internal projects, but some clients were against this, they wanted Java. I think that in some cases politics into companies could be problematic, if you are working with clients that have fear to any new or “not standard” thing, or contracts that duty you to use Java.
Using vavr allow us to apply most of the useful knowledge that we learned with Scala, but using Java.
The use of foldLeft with lists, or the use of Try instead try/catch, etc, all this is something we as Scala programmers usually miss from Java.

How and where

You can use vavr in any place with no problems, but there are some integrations that you will need.

Json

In order of integrate vavr types with Jackson, there is a package: vavr-jackson.
Then you must create a JsonCustomObjectMapper as describe Play documentation.

import com.fasterxml.jackson.databind.ObjectMapper;
import io.vavr.jackson.datatype.VavrModule;
import play.libs.Json;

public class JavaJsonCustomObjectMapper {
  JavaJsonCustomObjectMapper() {
    ObjectMapper mapper = Json.newDefaultMapper()
      .registerModule(new VavrModule());
    Json.setObjectMapper(mapper);
  }
}

Futures

For async programming in Java, CompletionStage is the interface for this.

We wanted Futures instead CompletionStage because the api feels more natural if you know Scala, and because why not ;)

To define a Future with vavr, you usually use .of():
static <T> Future<T> of(ExecutorService executorService, CheckedFunction0<? extends T> computation)

It mean, that vavr future use an ExcecutorService to provide the context execution. But Play usually use directly an Executor.
It is true for the HTTPExcecitionContext and for the DatabaseExecutionContext (used in the Ebean example app).

So, in order to transform those Excecutors into ExcecutorService, we can use this example by Viktor Klang:

This little Scala code allow us to transform an Excecutor in an ExecutorService:

protected ExecutorService getHttpExecutionService() {
    return ExecutionContextExecutorServiceBridge.apply((ExecutionContextExecutor) httpExecutionContext.current());
}

// ...

public CompletionStage<Result> removeWithFuture(Long id) {
    Future<Result> response = repository.delete2(id).flatMap(
      dbResult -> Future.of(getHttpExecutionService(), () ->
        dbResult.fold(error -> {
            return Results.status(Http.Status.CONFLICT, "Not removed"));
          },
          allOkay -> {
            ObjectNode js = Json.newObject().put("id", id);
            return Results.status(Http.Status.ACCEPTED, js);
          })
      ));

    return response
      .recover(ex -> {
        Logger.warn("Exception in removeWithFuture()", ex);
        return internalServerError("Ups...");
      })
      .toCompletableFuture();
  }

What problems will you have?, well, actually most of things work fine, except if you need ctx().args.get("...") or request(). They only works outside of a Future, so be careful.

Conclusions

At this moment, we are happy with the result, it is true that it is not the natural way for a Java programmer, but the use of vavr did the experience less awful.
I am sharing here my experiences, but I am curious to know if some else have been playing with vavr or so.

Thank you!

3 Likes

We’ve been using vavr with Play for a year now in one of our customer’s projects. Everything works fine but the instrumentation of vavr Futures with Kamon isn’t possible so far so the the distributed trace is lost once you get to spawn an thread with a vavr Future.

We’re currently working on a PR to kamon to make it able to work with vavr Futures.