Skip to main content

Google Guice: Dependency Injection with Guice 3.0

 
 
Guice (pronounced 'juice') is a lightweight dependency injection framework for Java 5 and above, from Google.

  • Mature Framework – Used in many open source projects like apache struts, apache shindig etc. Google is using it in many mission critical applications.
  • Simple and easy to use – It help in design better application.
  • JSR 330 support
  • AOP support
  • Very light weight – less then 1 MB in size
  • Won the 18th Jolt Award  - for best Library, Framework, or Component.


Google Guice with example


Lets consider very high level application design where need services, persistence layer and authentication mechanism. Each of the functionality is very different but very dependent on each other. If we start writing the code without giving much thought on design, then we will be ending with the code, which is very tightly couple, hard to change and even harder to test.

ApplicationArchitect
Application design


Application main class

public class Application {
 private final AppService service;
 private final AppPersist persist;
 private final AppAuthentication authenticator;

 @Inject
 public Application(AppService service, 
   AppPersist persist, 
   AppAuthentication authenticator) {
  this.service = service;
  this.persist = persist;
  this.authenticator = authenticator;
 }
 
 //Other application related code
}

Custom annotation class for user id binding

@BindingAnnotation
@Retention(RUNTIME)
@Target({ METHOD, FIELD, PARAMETER})
public @interface User {}



Service classes

public interface AppService {
 void doSomthing();
}



public class AppServiceImpl implements AppService{
 private final ServiceConfig config;
 private final AppPersist persist;
 private final AppAuthentication authenticator;
 private final String user;

 @Inject
 public AppServiceImpl(ServiceConfig config, 
   AppPersist persist, 
   AppAuthentication authenticator, 
   @User String user) {
  this.config = config;
  this.persist = persist;
  this.authenticator = authenticator;
  this.user = user;
 }

 @Override
 public void doSomthing() {
  //code
 }
}



Guice module – wiring the dependencies

public class AppModule extends AbstractModule{

 @Override
 protected void configure() {
  bind(Application.class);
  bind(AppService.class).to(AppServiceImpl.class);
  bind(AppPersist.class).to(AppPersistImpl.class);
  bind(AppAuthentication.class).to(AppAuthenticationImpl.class);
  bind(String.class).annotatedWith(User.class).toInstance("UserID");
 }

 @Provides
 public ServiceConfig getService1Configuration(){
  return new ServiceConfig();
 }

}

Application entry point - time to Bootstrap the Guice

public static void main(String... arg) { 
 Injector inject = Guice.createInjector(new Test1Module());
 Application app = inject.getInstance(Application.class);
 app.service.doSomthing();
}



How Guice find and inject the dependency?

Generally all the bindings are definition under Module classes (Module classes are subclass of AbstractModule class).

public class AppModule extends AbstractModule{

 @Override
 protected void configure() {
  bind(Application.class);
  bind(AppService.class).to(AppServiceImpl.class);
  ....
 }

 @Provides
 public ServiceConfig getService1Configuration(){
  return new ServiceConfig();
 }

}

After getting the binding configuration, Guice inject the dependency based on @Inject annotation. Here are few ways of defining the injection point.

1. Constructor binding

bind(Application.class);

Binding point

public class Application {
 ...
 @Inject
 public Application(AppService service,
   AppPersist persist,
   AppAuthentication authenticator) {
  this.service = service;
  this.persist = persist;
  this.authenticator = authenticator;
 }

}



2. Linked binding

It used for binding the interface to target implantation class.

bind(AppService.class).to(AppServiceImpl.class);
bind(AppPersist.class).to(AppPersistImpl.class);
bind(AppAuthentication.class).to(AppAuthenticationImpl.class);

3. Annotation binding

 bind(String.class).annotatedWith(User.class).toInstance("UserID");

And the binding point will be annotated with “@User” .

public class AppServiceImpl implements AppService{
 
 ...

 @Inject
 public AppServiceImpl(ServiceConfig config, 
   AppPersist persist, 
   AppAuthentication authenticator, 
   @User String user) {
  this.config = config;
  this.persist = persist;
  this.authenticator = authenticator;
  this.user = user;
 }
 
 ...
}



4. Providers methods

When Guice doesn't find the binding for injection point then it search for “@Provides” annotated method under module classes to resolve the type. These provider methods must be define under module classes.

 public class AppModule extends AbstractModule{
 ...

 @Provides
 public ServiceConfig getService1Configuration(){
  return new ServiceConfig();
 }

}



In below code we are using “ServiceConfig” class. Which doesn't have any defined binding, so Guice will resolve the dependency through Provider function.

public class AppServiceImpl implements AppService{
 ...

 @Inject
 public AppServiceImpl(ServiceConfig config, 
   AppPersist persist, 
   AppAuthentication authenticator, 
   @User String user) {
  this.config = config;
  this.persist = persist;
  this.authenticator = authenticator;
  this.user = user;
 }

 ...
}

Where we can use @Inject?

We can apply @Inject to

  • Constructor – It is a preferred way, because it encourage the immutable behaviour
  • Field – This kind of injection are hard to debug
  • Method




Unit Testing – Time to test the Application

We cannot consider application done-done, till it has sufficient amount of test coverage. The best part of DI framework is, it makes application loosely couple, so unit testing becomes more easer.

To test our sample application we need to change the user id, persistence implementation and service configuration, to align test execution with our testing environment. So we have to re-wire the bindings.

Here is the Test module for unit testing

public class AppTestModule extends AbstractModule{
 @Override
 protected void configure() {
  bind(AppPersist.class).to(AppTestPersistImpl.class);
  bind(String.class).annotatedWith(User.class).toInstance("TestUserID");
 }

 @Provides
 public ServiceConfig getService1Configuration(){
  return new ServiceTestConfig();
 }
} 


And below is the unit-test class for our application. In setup function we are overriding the “AppModule” with “AppTestModule”. So now we have “AppPersist” bind with “AppTestPersistImpl” and “UserID” with “TestUserID”. Apart from these changes, other bindings will be untouched.

public class AppTest {
 Injector injector;

 @Before
 public void setup(){
  injector = Guice.createInjector(Modules
     .override(new AppModule())
     .with(new AppTestModule()));
 }
 
 @Test
 public void testMyApp(){
  //TEST CODE
 }
}




Isn’t it simple? Here we have all dependences needed for unit testing without doing too much code change :)



Comments

Popular posts from this blog

ERROR: Ignored call to 'alert()'. The document is sandboxed, and the 'allow-modals' keyword is not set.

Recently I found this issue while writing code snippet in "JSFiddle". And after searching, found this was happening because of new feature added in "Chrome 46+". But at the same time Chrome doesn't have support for "allow-modals" property in "sandbox" attribute. Chromium issue for above behavior: https://codereview.chromium.org/1126253007 To make it work you have to add "allow-scripts allow-modals" in "sandbox" attribute, and use "window.alert" instead of "alert". <!-- Sandbox frame will execute javascript and show modal dialogs --> <iframe sandbox="allow-scripts allow-modals" src="iframe.html"> </iframe> Feature added: Block modal dialog inside a sandboxed iframe. Link: https://www.chromestatus.com/feature/4747009953103872 Feature working Demo page: https://googlechrome.github.io/samples/block-modal-dialogs-sandboxed-iframe/index.html

Application Design Notes

Don’t be afraid to write your own code, but be absolutely sure you need to Don't reinvent the wheel Learn more about your libraries and take full advantage  Date time calculation is hard ( leap second ,  leap year ), use trusted library  js-joda ,  momentJs ,  joda (java) Simple is better than perfect (nearly) every time If you can deliver a sub-optimal solution (that solves the problem but has known limitation) in a week instead of a full featured one in a month DO, IT Simple system are Easy to reason about  Easy to debug Easy to refactor Easy to learn Simple doesn't mean you skip good engineering, but you can use duct tape. Build things the right way from the start, refactoring is hard and expensive Security Manage and store passwords securely Telemetry Common retrofitting "grunt work" Internationalization + localization Web Content Accessibility Factoring and styling HTML UI Adding unit test to an existing codebase LOG LOG LOG Log, but do it right We spend lot of t

How to store user password at server!!!

Trick is, you should never store user password… never ever. Now the real question is, then how to authenticate and authorize the user with password. And answer is when user enter the password, we should encrypt the password and store the hints. So next time when user enter the password we follow the same process and compare hints, if both hints are same then password is matched, else it is wrong password. Next question will be, what kind of hints, and how to generate these hints. In simple term hints are the obfuscated and fragmented form of user password. And very important part is hints generation process, which have to be collision resistant , means there will be very less possibility to find the data which generate same hints (like Cryptographic hashing functions ). Below is the simple checklist of password hashing and storing, which you should always keep in mind. PS You're Probably Storing Passwords Incorrectly Storing Passwords - done rig