Wednesday, July 13, 2016

Dependency injection with Guice in Play

Guice is the default dependency injection (further DI) framework of Play. Other frameworks may be used as well, but using Guice makes development efforts easier, since Play takes care for things under the veil.
The official Play DI manual does not provide sufficient explanation. This post is the first in the sequence of posts, explaining in the different way and in more details, how DI with Guice should be done.


Injection of Play API-s with Guice


Starting from Play 2.5 several API-s, which were static in the earlier versions, should be created with DI. These are, for example, Configuration, JPAApi, CacheApi, etc.
Injecting method of these API-s depends, in what class this should be done: a class, which is automatically injected by Play or a custom class.

Injection from an automatically injected class is just as simple as putting appropriate @Inject annotation on either field or constructor. For example, to inject Configuration in a controller with property injection:
 @Inject 
 private Configuration configuration;
or with constructor injection:
 private Configuration configuration;
 @Inject
 public MyController(Configuration configuration) {
     this.configuration = configuration;
 }
Injection from a custom class, which has injection binding, should be done just like it is done for automatically injected class - with @Inject annotation.

Injection from a custom class, which is not injected by itself, should be done by explicit call to the injector with Play.current().injector(). For example, to inject Configuration in a custom class define a configuration data member like this:
private Configuration configuration = Play.current().injector().instanceOf(Configuration.class);

Injection of WSClient and Application


Both WSClient and Application may be injected with @Inject annotation like in the example:
 public class MyApplication extends Controller {  
      private Configuration configuration;  
      private Application applicationProvider;  
      private WSClient wsClientProvider;  
      @Inject  
      public MyApplication(Configuration configuration, Application applicationProvider, WSClient wsClientProvider) {  
           this.configuration = configuration;  
           this.applicationProvider = applicationProvider;  
           this.wsClientProvider = wsClientProvider;  
      }  
     ...  
 }  
The official documentation example for WSClient uses this very injecting method.

Such injection method is not good enough for the following reasons:
1. The whole dependency tree is injected upon injecting of the MyApplication instance.
2. Due to injecting of the whole tree, a unit test for the MyApplication will not work: it will fail with the ProvisioningException.

The preferred way of injecting the WSClient and Application is with injection provider:
 public class MyApplication extends Controller {  
      private Configuration configuration;  
      private Provider<Application> applicationProvider;  
      private Provider<WSClient> wsClientProvider;  
      @Inject  
      public MyApplication (Configuration configuration,   
                Provider<Application> applicationProvider,  
                Provider<WSClient> wsClientProvider) {  
           this.configuration = configuration;  
           this.applicationProvider = applicationProvider;  
           this.wsClientProvider = wsClientProvider;  
      }  
     ...  
 }  
When injection of the Provider<WSClient> the instance of the WSClient is not injected. It will be injected only on call to the Provider get() method:
 WSRequest request = wsClientProvider.get().url("Some Url");

More reading


See the dedicated post Custom injection binding in Guice with Play.

See the dedicated post Using Guice for Play tests

See working examples on Git.

No comments :

About the author

My Photo
I trust only simple code and believe that code should be handsome. This is not a matter of technology, but professional approach, consolidated after years of software development. I enjoy to cause things working and feel very happy, when I manage to solve a problem.
Back to Top