Dagger and Play 2 Java
I recently got the occasion of trying out Play 2 in Java and i must say the Play 2 Framwork looks actually really good in Java too.
But, of course... there is a but, one of the few things that strikes you first, and i must say with great intensity, is the mandatory static methods that you must put in your Controllers in order to define your routes. Exemple :
[code language=”java”]
// in app/controllers/Application.java
package controllers;
import play.mvc.Controller;
import play.mvc.Result;
import service.CoffeeService;
import views.html.index;
public class Application extends Controller {
public static Result index() {
return ok(index.render(“Your application is ready.”));
}
}
[/code]
And with the routes defined as such :
[code]
# Home page
GET / controllers.Application.index()
[/code]
This is relatively great... if you like starting off with the wrong foot. I won't talk about modularization or the danger of spaghetti-code, neither will i argue that this is not great for testing controllers that will use services or any other kind of external dependencies.
Luckily, the Play 2 Framwork people have thought long and hard when they designed their systems, and if they won't force you to use any kind of dependency injection systems, they'll allow you to plugin-in your preffered choice. This is clearly documented here but this is in Scala and you might think it's not available for Play 2 Java, and you would be wrong.
So here's a little example on how to do it with a really great project by the teams at Square called Dagger. Dagger relies on the annotation processing framework of Java to be able to plug itself as an extra step of the compiler and try, as much as possible, to do dependency injection checks (and maybe more) at compile-time. So let's try to use it in a simple Java app :
[code]
// in build.sbt - we’ll add the dependency
name := “app”
version := “1.0-SNAPSHOT”
libraryDependencies ++= Seq(
javaJdbc,
javaEbean,
cache,
“com.squareup.dagger” % “dagger” % “1.2.2”,
“com.squareup.dagger” % “dagger-compiler” % “1.2.2”
)
play.Project.playJavaSettings
[/code]
[code language=”java”]
// in app/controllers/Application.java - we’ll inject a simple Service via dagger
package controllers;
import play.mvc.Controller;
import play.mvc.Result;
import service.CoffeeService;
import views.html.index;
import javax.inject.Inject;
public class Application extends Controller {
private CoffeeService coffeeService;
@Inject
public Application(CoffeeService service) {
coffeeService = service;
}
public Result index() {
return ok(index.render(“Your application " + this.toString() +” is ready. " + coffeeService.toString()));
}
}
[/code]
Finally to make it all work we need to change the routes file and override the “Global” configuration class :
[code language=”java”]
// in app/Global.java - we’ll create this class and override the controller instance creation
import dagger.ObjectGraph;
import module.ProductionModule;
import play.Application;
import play.GlobalSettings;
public class Global extends GlobalSettings {
private ObjectGraph objectGraph;
@Override
public void beforeStart(Application app) {
super.beforeStart(app);
objectGraph = ObjectGraph.create(new ProductionModule());
}
@Override
public A getControllerInstance(Class controllerClass) throws Exception {
return objectGraph.get(controllerClass);
}
}
[/code]
and
[code]
# Home page
GET / @controllers.Application.index()
[/code]
The @controllers.Application.index() tells the whole system that now he has to create a new instance of Application controller and he will get the controller's instance through the overriden method in Global.
The goal was not in this article to teach you how to use Dagger or Play, rather more to show you how the two of them can work together. If you want to see the whole project, it's available online on https://github.com/lateralthoughts/dagger-play-di-example. So if you want to know more, clone the project and play with it. Any feedback would be appreciated.
Vale