Books

In order to better fit in to the Java 8 ecosystem, and to allow Play Java users to make more idiomatic use of Java in their applications, Play has switched to using a number of Java 8 types such as CompletionStage and Function. Play also has new Java APIs for EssentialAction, EssentialFilter, Router, BodyParser and HttpRequestHandler.

There are several API changes to accommodate writing filters and HTTP request handlers in Java, in particular with the HttpRequestHandler interface. If you are using Scala for these components you are still free to use the Scala API if you wish.

The HttpRequestHandler actually existed in Play 2.4, but now it serves a different purpose. The createAction and wrapAction methods have been moved to a new interface called ActionCreator, and are deprecated in HttpRequestHandler. These methods are only applied to Java actions, and are used to intercept requests to the controller’s method call, but not all requests.

In 2.5, HttpRequestHandler’s main purpose is to provide a handler for the request right after it comes in. This is now consistent with what the Scala implementation does, and provides a way for Java users to intercept the handling of all HTTP requests. Normally, the HttpRequestHandler will call the router to find an action for the request, so the new API allows you to intercept that request in Java before it goes to the router.

You must supply the HTTP execution context explicitly as an executor when using a Java CompletionStage inside an Action, to ensure that the HTTP.Context remains in scope. If you don’t supply the HTTP execution context, you’ll get “There is no HTTP Context available from here” errors when you call request() or other methods that depend on Http.Context.

A big change in Play 2.5 is the change to use standard Java 8 classes where possible. All functional types have been replaced with their Java 8 counterparts, for example F.Function1<A,R> has been replaced with java.util.function.Function<A,R>.

The move to Java 8 types should enable better integration with other Java libraries as well as with built-in functionality in Java 8.

Unlike the Play functional interfaces, the Java 8 functional interfaces don’t permit checked exceptions to be thrown. If your lambda expressions throw a checked exception then you’ll need to change the code. (If you don’t throw checked exceptions then you can leave the code unchanged.)

You may get a lot of compiler errors but it’s pretty easy to get your code working again. Let’s suppose your Play 2.4 code uses a F.Callback0 lambda to stop a database:

onClose(() -> {
database.stop(); // <-- can throw an IOException
})

In Play 2.5 the onClose method has been changed to take a java.lang.Runnable argument instead of F.Callback0. Because Runnables can’t throw checked exceptions the code above won’t compile in Play 2.5.

To get the code to compile you can change your lambda code to catch the checked exception (IOException) and wrap it in an unchecked exception (RuntimeException). It’s OK for a Runnable to throw an unchecked exception so the code will now compile.

Step 1: Change all code that returns F.Promise to return CompletionStage instead. To aid with migration, F.Promise also implements the CompletionStage interface, which means any existing code that returns Promise can still be invoked from code that has been migrated to use CompletionStage.

Replace code that uses F.Option with Optional. The two types are similar, but their API is different, so you will need to update your code. The main difference between the two types is that while F.Option inherits java.util.Collection, Optional doesn’t.

Here follows a short table that should ease the migration:

F.Option

Optional

F.Option.None()

Optional.empty()

F.Option.Some(v)

Optional.ofNullable(v)

o.isDefined()

o.isPresent()

o.isEmpty()

!o.isPresent()

o.get()

o.get()

o.getOrElse(f)

o.orElseGet(f) or o.orElse(v)

o.map(f)

o.map(f)

Optional has a lot more combinators, so we highly encourage you to learn its API if you are not familiar with it already.

Several static APIs were deprecated in Play 2.5, in favour of using dependency injected components. Using static global state is bad for testability and modularity, and it is recommended that you move to dependency injection for accessing these APIs. You should refer to the list in the Play 2.4 Migration Guide to find the equivalent dependency injected component for your static API.