Update 23/07/2015 : How to add stop hooks for your modules, how to inject play modules (WSClient, I18n, Cache, …) Update 15/12/2015 : How to configure Play logs and Http filters
Play Framework, in its new version, provides a lot of new stuff to handle dependency injection at runtime, using Guice.
With Scala, I always prefer using compile time dependency injection, as it allows to see errors as soon as possible. I must also admit that I find compile time DI a lot more elegant as it needs no container or proxy at runtime!
Fortunately, Play team also added the ability to control the way routes, controllers and other components are binded together at compile time.
Controller and service
In this example, we have a controller that takes a LinkService dependency.
We want to be able to mock this service in our controller tests.
The routes file is defined as follows :
How to wire this
To have a fully functional application we need to tell the Play router how to find our LinkService dependency and how to wire it into our controller.
This can be done by defining a custom ApplicationLoader :
Note : the Routes constructor is generated by Play at compile time, depending on the controllers referenced in the routes file.
To enable this configuration we need to add this line in application.conf :
play.application.loader=SimpleApplicationLoader
And this line in build.sbt :
routesGenerator := InjectedRoutesGenerator
How to test it
In this example, the tests will be written using Specs2.
To test our controller, we can easily wire a mocked linkService :
To be able to test the routes directly with our real services, e.g. for integration tests, we need to define our own ‘WithApplication’ helper :
Of course if you want your router to use controllers with mocked services, you can define a new ApplicationLoader for tests instead of our SimpleApplicationLoader.
Then, we can use WithDepsApplication in our tests :
Note that you can also use macwire macros to wire automatically services, controllers and routes. A good example can be found here.
How to inject Play modules
As Ryan pointed out in the comments, it is possible to inject modules provided by Play APIs.
The BuiltInComponentsFromContext can be mixed with several traits, provided by the framework.
Let’s consider that our link service needs to use the Web service client API :
To inject an instance of WS client in your controller, you have to mix BuiltInComponentsFromContext with the NingWSComponents trait and then pass the wsClient to your service :
You may need to add some behavior to your dependencies when your application is stopped. BuiltInComponentsFromContext contains an applicationLifecycle value, which is a DefaultApplicationLifecycle.
This class provides an addStopHook method. You can pass an asynchronous function to this method, that will be executed when your application will be stopped.
In this example, we are using LinkService cleanup method in the stop hook :
Important note : stop hooks are called in the reverse order they have been added in applicationLifecycle.
You can find the sources of this examples in this Github project.
Next time we will see another new feature of Play 2.4, its (experimental) integration with Akka-Streams!
More tips
When you’re using compile time dependency injection with Play, some basic stuff that used to work out of the box don’t work anymore.
To activate Play logs, you need to add this line in the ApplicationLoader :
So the SimpleApplicationLoader definition looks like :
To activate Http filters (or essential filters), you need to override a value from BuiltInComponentsFromContext :
So the ApplicationComponents definition looks like :