A long term strategy for Play is to remove Play’s dependence on global state. Play currently stores a reference to the current application in a static variable, and then uses this variable in many places throughout its codebase. Removing this has the following advantages:

Applications become easier to test and components become easier to mock.

More interesting deployment scenarios are possible, such as multiple Play instances in a single JVM, or embedding a lightweight Play application.

The application lifecycle becomes easier to follow and reason about.

Removing Play’s global state is however a big task that will require some disruptive changes to the way Play applications are written. The approach we are taking to do this is to do as much as possible in Play 2.4 while maintaining backwards compatibility. For a time, many of Play’s APIs will support both methods that rely on require global state and methods that don’t rely on global state, allowing you to migrate your application to not depend on global state incrementally, rather than all at once when you upgrade to Play 2.4.

The first step to removing global state is to make it such that Play components have their dependencies provided to them, rather than looking them up statically. This means providing out of the box support for dependency injection.

In the Java ecosystem, the approach to dependency injection is generally well agreed upon in JSR 330, but the right implementation is widely debated, with many existing competing implementations such as Guice, Spring and JEE itself.

In the Scala ecosystem, the approach to dependency injection is not generally agreed upon, with many competing compile time and runtime dependency injection approaches out there.

Play’s philosophy in providing a dependency injection solution is to be unopinionated in what approaches we allow, but to be opinionated to the approach that we document and provide out of the box. For this reason, we have provided the following:

One of the biggest advantages of introducing dependency injection to Play is that many parts of Play can now be much easier to test. Play now provides a number of APIs to assist in mocking and overriding components, as well as being able to test interactions with Play components in isolation from the rest of your Play application.

It is now straightforward to embed a Play application. Play 2.4 provides both APIs to start and stop a Play server, as well as routing DSLs for Java and Scala so that routes can be embedded directly in code.

Play now supports aggregating reverse routers from multiple sub projects into a single shared project, with no dependency on the project the routes files came from. This allows a modular Play application to use the Play reverse router as an API between modules, allowing them to render URLs to each other without depending on each other. It also means a dependency free reverse router could be extracted out of a Play project, and published, for use by external projects that invoke the APIs provided by the project.

Play 2.4 now requires JDK 8. Due to this, Play can, out of the box, provide support for Java 8 data types. For example, Play’s JSON APIs now support Java 8 temporal types including Instance, LocalDateTime and LocalDate.

The Play documentation now shows code examples using Java 8 syntax for anonymous inner classes. As an example, here’s how some of the code samples have changed:

Play provides two new experimental features. These are labelled as experimental because the APIs for them have not yet been finalised, and may change from one release to the next. Binary compatibility is not guaranteed on these APIs.

Play provides an iteratees based implementation of Reactive Streams, allowing other Reactive Streams implementations, such as Akka Streams or RxJava, to be used with Play’s iteratee IO APIs. For more information, see Reactive Streams Integration.