Play! Framework + Google Guice
Play has a module for integrating Guice:
http://www.playframework.org/modules/guice-1.2/home
In addition to the module documentation, this post from @_felipera can help you get started.
http://geeks.aretotally.in/dependency-injection-with-play-framework-and-google-guice
How to use the Guice module
Add the dependency
require: - play - play -> guice 1.2
Download the dependencies
play deps
Create a new class that will be injected in the controller
services.MyService
package services; public interface MyService { public void sayHello(); }
services.MyServiceImpl
package services; public class MyServiceImpl implements MyService { public MyServiceImpl(){ play.Logger.info("constructor!"); } @Override public void sayHello() { play.Logger.info("hello"); } }
Configure the injector
package config; public class GuiceConfig extends GuiceSupport { @Override protected Injector configure() { return Guice.createInjector(new AbstractModule() { @Override protected void configure() { bind(MyService.class).to(MyServiceImpl.class).in(Singleton.class); } }); } }
This will setup the class as a singleton. Each time a class has the dependency of MyService, the injector will inject the same instance of MyServiceImpl.
Inject the dependency using the @Inject annotation
package controllers; public class Application extends Controller { @Inject static MyService myService; public static void index() { myService.sayHello(); render(); } }
Testing
My next step was to create a test and here came the first problem
play test
http://localhost:9000/@tests
Compilation error! The problem is that the module has a folder called ‘test’. This folder should have some unit or functional test, but instead it has three sample applications. The convention in play modules is to have these kind of applications in the ‘samples-and-test’ folder.
I made a fork of the project to rename this folder:
https://github.com/axelhzf/play-guice-module
I also did a pull-request but I didn’t get any response so far :
https://github.com/pk11/play-guice-module/pull/5
Renaming the folder ‘test’ was enough to run this test:
@InjectSupport public class InjectTest extends UnitTest { @Inject static MyService myService; @Test public void injectOk(){ assertNotNull(myService); } }
Adding more dependencies
By default, Play automatically detects the @Inject annotation on classes than inherit from Controller, Job and Mail. If you want to inject dependencies on other classes you must use the @InjectSupport.
Typically our services are not as simple as MyService. It is common to have dependencies between services. Guice solves this problem analyzing the dependencies and instantiating the objects in the proper order.
services.MyDependentService
package services; public interface MyDependentService { public void sayHelloWorld(); }
service.MyDependentServiceImpl
package services; @InjectSupport public class MyDependentServiceImpl implements MyDependentService { @Inject static MyService myService; public MyDependentServiceImpl(){ play.Logger.info("Init MyDependentServiceImpl"); } public void sayHelloWorld(){ myService.sayHello(); play.Logger.info("world"); } }
InjectTest
@InjectSupport public class InjectTest extends UnitTest { @Inject static MyDependentService myDependentService; @Test public void injectOk(){ assertNotNull(myDependentService); myDependentService.sayHelloWorld(); } }
Binding in GuiceConfig
bind(MyDependentService.class).to(MyDependentServiceImpl.class).in(Singleton.class);
And this is the console output
20:34:39,090 INFO ~ Init MyServiceImpl 20:34:39,095 INFO ~ Init MyDependentServiceImpl 20:34:39,095 INFO ~ Application 'lazySingleton' is now started ! 20:34:39,136 INFO ~ hello 20:34:39,136 INFO ~ world
Constructor injection
One of the things I don’t like about the module is that the fields you are allowed to inject must be static. I would prefer to declare the dependencies as constructor parameters. This way, it would be more obvious that to create an instance of MyDependentServiceImpl you need a MyService instance. Moreover, when working on units test, it’s easier to pass a mock objects as a parameter than to configure an injector.
In the module documentation I didn’t found any reference to how to do it. Nevertheless, I found an article explaining how to do this using a Provider:
http://ericlefevre.net/wordpress/2011/05/08/play-framework-and-guice-use-providers-in-guice-modules/
Later, I found a question on StackOverflow that gave me another clue:
http://stackoverflow.com/questions/8435686/does-injector-getinstance-always-call-a-constructor
In the Edit he says that he forgot to put the @Inject annotation in the constructor. I tried to do the same thing and finally it worked:
public class MyDependentServiceImpl implements MyDependentService { private final MyService myService; @Inject public MyDependentServiceImpl(MyService myService){ this.myService = myService; play.Logger.info("Inicializando MyDependentServiceImpl"); } ...
Lazy Singletons
It still remains one last detail to have a perfect google guice configuration.
The services are initialized when the application starts.
21:38:11,801 INFO ~ Inicializando MyServiceImpl 21:38:11,805 INFO ~ Inicializando MyDependentServiceImpl 21:38:11,805 INFO ~ Application 'lazySingleton' is now started !
When the application is in production mode this is the correct behavior. But in development mode I prefer that Singletons are intialized on demand. There may be services that take their time to start and I want the application startup to be as fast as possible.
With Google Guice you can achieve this using Scopes:
http://code.google.com/p/google-guice/wiki/Scopes
All you have to do is to set the Stage parameter:
Stage stage = Play.mode.isDev() ? Stage.DEVELOPMENT : Stage.PRODUCTION; return Guice.createInjector(stage, new AbstractModule() {…..
Rerunning the test
22:00:03,353 WARN ~ You're running Play! in DEV mode 22:00:04,615 INFO ~ Connected to jdbc:h2:mem:play;MODE=MYSQL;LOCK_MODE=0 22:00:04,811 INFO ~ Guice injector created: config.GuiceConfig 22:00:04,819 INFO ~ Init MyServiceImpl 22:00:04,824 INFO ~ Init MyDependentServiceImpl 22:00:04,824 INFO ~ Application 'lazySingleton' is now started !
Ooops! The Singleton are initialized before application starts. Perhaps that’s not the correct use for the stage variable. Let’s try a test:
public class StageTest { @Test public void testDevelopment(){ Injector injector = createInjector(Stage.DEVELOPMENT); System.out.println("development - before getInstance"); MyService instance = injector.getInstance(MyService.class); System.out.println("development - after getInstance"); } @Test public void testProduction(){ Injector injector = createInjector(Stage.PRODUCTION); System.out.println("production - before getInstance"); MyService instance = injector.getInstance(MyService.class); System.out.println("production - after getInstance"); } public Injector createInjector(Stage stage){ Injector injector = Guice.createInjector(stage, new AbstractModule(){ @Override protected void configure() { bind(MyService.class).to(MyServiceImpl.class); } }); return injector; } }
And the result is:
INFO: development - before getInstance INFO: Inicializando MyServiceImpl INFO: development - after getInstance INFO: Inicializando MyServiceImpl INFO: production - before getInstance INFO: production - after getInstance
Just like it says on the documentation, in development mode Singletons are initialized lazily.
If this works, when I tried using the play module why didn’t it work?
Reviewing the code:
https://github.com/pk11/play-guice-module/blob/master/src/play/modules/guice/GuicePlugin.java
@OnApplicationStart the module finds all classes annotated with @InjectSupport and inject it’s dependencies. To inject the dependencies the module calls the getBean() method. And here we find the problem: when calling getBean() the class is instantiated.
I found a solution to this problem:
https://groups.google.com/d/msg/google-guice/405HVgnCzsQ/fBUuueP6NfsJ
This is the code:
These classes create a proxy for each class annotated as @LazySingleton. When the object is injected the injector actually injects the proxy. The first time a method is invoke, the proxy will take care of initializing the class.
Using these classes, the injector configuration looks like:
public class GuiceConfig extends GuiceSupport { @Override protected Injector configure() { Stage stage = Play.mode.isDev() ? Stage.DEVELOPMENT : Stage.PRODUCTION; return Guice.createInjector(stage, new AbstractModule() { @Override protected void configure() { bindScope(LazySingleton.class, MoreScopes.LAZY_SINGLETON); bindLazySingletonOnDev(MyService.class, MyServiceImpl.class); bindLazySingletonOnDev(MyDependentService.class, MyDependentServiceImpl.class); } protected <T> void bindLazySingletonOnDev(Class<T> expected, Class<? extends T> implClass){ if(Play.mode.isDev()){ bind(implClass).in(MoreScopes.LAZY_SINGLETON); Provider<T> provider = LazyBinder.newLazyProvider(expected, implClass); bind(expected).toProvider(provider); }else{ bind(expected).to(implClass).in(Scopes.SINGLETON); } } }); } }
I will add this classes to the fork in order to have a complete module that can be reused across projects.
Conclusion
In the last few years Dependency Injection has has evolved from being an obscure and little understood term, to become part of every programmer’s toolchest. In this article we saw how easy is to integrate Guice, a very handy library from Google, into a play framework application. Moreover, we also covered how to customize it’s behaviour for a better development experience.
Article original published at http://axelhzf.tumblr.com.
Reference: Playframework + Google Guice from our JCG partner Sebastian Scarano at the Having fun with Play framework! blog.