§What’s new in Play 2.4
This page highlights the new features of Play 2.4. If you want learn about the changes you need to make to migrate to Play 2.4, check out the Play 2.4 Migration Guide.
§Dependency Injection
Play now supports dependency injection out of the box.
§Motivation
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 uprgade 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.
§Approach
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:
- An implementation that uses Guice out of the box
- An abstraction that allows other JSR 330 implementations to be plugged in
- All Play components can be instantiated using plain constructors or factory methods
- Traits that instantiate Play components that can be mixed together in a cake pattern like style to assist with compile time dependency injection
You can read more about Play’s dependency injection support for Java and Scala.
§Testing
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.
You can read about these new APIs here:
- Configuring Guice components in Java and Scala
- Testing database access code in Java and Scala
- Testing web service client code in Java and Scala
§Embedding Play
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.
In Java, see Embedding Play as well as information about the Routing DSL.
In Scala, see Embedding Play as well as information about the String Interpolating Routing DSL.
§Aggregated reverse routers
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.
For details on how to configure this, see Aggregating Reverse Routers.
§Java 8 support
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:
Before:
return promise(new Function0<Integer>() {
public Integer apply() {
return longComputation();
}
}).map(new Function<Integer,Result>() {
public Result apply(Integer i) {
return ok("Got " + i);
}
});
After:
return promise(() -> longComputation())
.map((Integer i) -> ok("Got " + i));
§Maven/sbt standard layout
Play will now let you use either its default layout or the directory layout that is the default for Maven and SBT projects. See the Anatomy of a Play application page for more details.
§Anorm
Anorm has been extracted into a separate project with its own lifecycle, allowing anorm to move at its own pace, not bound to Play. The anorm project can be found here.
New features in anorm include:
- New positional getter on
Row
. - Unified column resolution by label, whatever it is (name or alias).
- New streaming API; Functions
fold
andfoldWhile
to work with result stream (e.g.SQL"Select count(*) as c from Country".fold(0l) { (c, _) => c + 1 }
). FunctionwithResult
to provide custom stream parser (e.g.SQL("Select name from Books").withResult(customTailrecParser(_, List.empty[String]))
). - Supports array (
java.sql.Array
) from column (e.g.SQL("SELECT str_arr FROM tbl").as(scalar[Array[String]].*)
) or as parameter (e.g.SQL"""UPDATE Test SET langs = ${Array("fr", "en", "ja")}""".execute()
). - Improved conversions for numeric and boolean columns.
- New conversions for binary columns (bytes, stream, blob), to parsed them as
Array[Byte]
orInputStream
. - New conversions for Joda
Instant
orDateTime
, fromLong
,Date
orTimestamp
column. - Added conversions to support
List[T]
,Set[T]
,SortedSet[T]
,Stream[T]
andVector[T]
as multi-value parameter. - New conversion to parse text column as UUID (e.g.
SQL("SELECT uuid_as_text").as(scalar[java.util.UUID].single)
).
§Ebean
Play’s Ebean support has been extracted into a separate project with its own lifecycle, allowing Ebean support to move at its own pace, not bound to Play. The play-ebean project can be found here.
play-ebean now supports Ebean 4.x.
§HikariCP
HikariCP is now the default JDBC connection pool. Its properties can be directly configured using .conf
files and you should rename the configuration properties to match what is expected by HikariCP.
§WS
WS now supports Server Name Indication (SNI) in HTTPS – this solves a number of problems with HTTPS based CDNs such as Cloudflare which depend heavily on SNI.
§Experimental Features
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.
§Akka HTTP support
Play supports a new Akka HTTP backend, as an alternative to the current Netty backend. For instructions on using it, see Akka Http Server.
§Reactive Streams Support
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.
Next: Migration Guides