Play Framework Dependency Injection

Posted by n3integration on November 13, 2015

If you are unfamiliar with the Play! Framework, it’s an MVC framework written in Scala and definitely worth checking out, especially if you’re a Java or Scala developer. One constraint of the framework that I have never really been fond of was the requirement for controllers to require static methods for routing purposes.

What is wrong with static methods? Two disadvantages come to mind:

  1. Testability
  2. Extensibility

One of the most common solutions for these constraints is the use of dependency injection, or DI. As of release of version 2.4, the Play Framework now provides built in support for DI using Guice. I had previously only used the Spring Framework, but was fortunate enough to attend a talk a few years back where Bob Lee pointed out some disadvantages of Spring and introduced Guice as an alternative. With the introduction of JSR-330 and the collection of @Inject annotations, it is fairly trivial to swap between frameworks.

Controllers

Although developers can continue to use controllers with static methods, it is much more advantageous and more of a best practice to use dependency injection instead. So, how do you define a controller to make use of the framework’s dependency injection? You define a POJO.

package controllers;

import play.mvc.*;

public class AdminController extends Controller {
  public Result log() {
    return TODO;
  }
}

Routes

When declaring a route in the routes file, the controller must be prefixed with an @ to indicate that Play should use an instance of the controller instantiated through the framework and invoke its instance method rather than a static method.

# <METHOD> <PATH>         <CONTROLLER>
GET        /admin/log    @controllers.AdminController.log()

Services

Being that controllers should be lightweight, the business logic should take place within services. Services can easily be injected into controllers using the @Inject annotation.

Service

The service should be defined with the @Singleton annotation attached to the class.

@Singleton
public class LogService {
  public LogService() {
    ...  
  }
  ...
}
Controller

The controller can be rewritten to use the service via constructor dependency injection.

public class AdminController extends Controller {

  private final LogService logService;

  @Inject
  public AdminController(LogService logService) {
    this.logService = logService;
  }
}

For basic dependency injection, that’s it! No need to import any additional dependencies, no XML files, and no ApplicationContext.