In an attempt to orient myself and my colleagues with GWT, I've been reading up on GWT, trying things out, and blogging about them here. My goal is to start with simple use cases and build on to them with more complex ones. The way it's been working so far is that each post builds on the prior one.

Thursday, February 18, 2010

Instance Creation and Dependency Injection and GIN

In the prior posts, we’ve taken a high-level look at the various Java classes we’d need to build the client side of an MVP Contact Management application. We saw how to build a testable ContactDetail UI component. We saw how to build a testable ContactList UI component. However, the thing that wires them together, the AppController, is not all that testable. It has code in it that looks like the following:
	private void initContactDetailPresenter(){
ContactDetailViewImpl contactDetailViewImpl = new ContactDetailViewImpl();
contactDetail = new ContactDetailPresenter(contactDetailViewImpl);
}

AppController is directly constructing a ContactDetailViewImpl and, therefore, we cannot mock the ContactDetailView in an attempt to test the AppController. One approach to solve this would be to create a factory that we could use to get the ContactDetailView implementation.

public interface AppFactory {
ContactDetailView getContactDetailView();
ContactListView getContactListView();
}

public class AppFactoryImpl implements AppFactory {
ContactDetailView getContactDetailView(){
return new ContactDetailViewImpl();
}
ContactListView getContactListView(){
return new ContactListImpl();
}
}

Now our initContactDetailPresenter() method could look like so:<

private void initContactDetailPresenter(AppFactory appFactory){
ContactDetailView contactDetailView = appFactory.getContactDetailView();
contactDetail = new ContactDetailPresenter(contactDetailView);
}

Then at test time, we could re-implement that factory so it returns a mock ContactDetailView.

public class MockAppFactory implements AppFactory{
ContactDetailView getContactDetailView(){
return createNiceMock(ContactDetailView.class);
}
ContactListView getContactListView(){
return createNiceMock(ContactListView.class);
}
}

One thing worth noting is that, as object construction goes, we’re not only creating a ContactDetailView, but we’re also injecting it in to the ContactDetailPresenter since ContactDetailPresenter has a dependency on a ContactDetailView implementation. This is DI -- dependency injection (see DI link for more information). We have used dependency injection frameworks in Java code to make each application unit testable and loosely coupled to the other units in the application. Such a framework would enable us to do things like have the ContactDetailPresenter already have the ContactDetailView injected in to it. In “normal” Java code, we might have accomplished this with the Spring dependency injection framework. However, Spring is not a GWT module so that is not available to use in client-side GWT code. It turns out that Google has developed a very capable Java dependency injection framework called Guice and this is also not a GWT module. However, it also turns out that they’ve developed a client-side equivalent to Guice which is called Gin and with Gin, we can do all the dependency injection we need.

Let’s keep looking at the Contact Management code to see what Gin will do for us. With our factory approach, we developed an AppFactory implementation which created the appropriate ContactDetailView and ContactListView implementations. Before we do anything, we’re going to change our terminology to use the word “injector” instead of factory. In an application that heavily uses DI, factories become less of a prominent feature so that’s one good reason to change terms. Also, the GIN framework and documentation and sample applications all use the term “injector” so it will be better if we are speaking the same language. The first thing Gin does is eliminate the need to implement factories. All that’s needed instead is a “module” to tersely say which implementation should be used for a particular interface.



public class AppGinModule extends AbstractGinModule{
@Override
protected void configure() {
bind(ContactListView.class).to(ContactListViewImpl.class);
bind(ContactDetailView.class).to(ContactDetailViewImpl.class);
}
}

Then our injector (previously factory) interface, via an annotation, specifies the module which has the configuration:

@GinModules(AppGinModule.class) 
public interface AppInjector extends Ginjector{
ContactDetailView getContactDetailView();
ContactListView getContactListView();
}

In our entry point, we can now call GWT.create() to have Gin return an implementation of our injector (previously factory). This injector’s methods now return the appropriate interface implementations based the module configuration:

AppInjector appInjector = GWT.create(AppGinModule.class);


This is sort of cool. We’ve defined our injector implementation with these bind().to() method calls in a configuration. Also, this configuration is fully within the core Java language, no XML files. This means it is fully type-safe, not possible to have spelling errors. This means that it is trivial using a Java IDE to find references to the ContactDetailViewImpl and see the Gin Module that is using it and how it is being used. It also means it gives us the ability to do safe refactoring if we need to rename classes, move them to different packages, etc.



But we can do more than just implementation selection. Gin can also construct ContactListPresenter and ContactDetailPresenter for us and inject its view implementation dependencies. Then our AppController doesn’t need to get the ContactDetailView from the AppInjector at all. All it needs is to do is get the ContactDetailPresenter from the AppInjector and Gin will take care of injecting the appropriate view in to the presenter.



There are two things we need to do to make this happen:



1) We need to add getContactListPresenter() and getContactDetailPresenter() methods to our AppInjector interface and



2) We need to annotate the presenters’ constructors with an @Inject annotation to let Gin know it can inject dependencies in to it.



Since ContactListPresenter and ContactDetailPresenter are not interfaces, the Gin Module configuration does not need to change at all. Also, since our AppController no longer needs to get instances of the views directly, those can be removed from the AppFactory interface. Now the interface looks like:



@GinModules(AppGinModule.class) 
public interface AppInjector extends Ginjector{
public ContactListPresenter getContactListPresenter();
public ContactDetailPresenter getContactDetailPresenter();
}


And the constructor to ContactDetailPresenter with its annotation looks like:



@Inject
public ContactDetailPresenter(ContactDetailView contactDetailView){
this.contactDetailView = contactDetailView;
}


Now the AppController can simply init its ContactDetailPresenter like so:



	private void initContactDetailPresenter(AppFactory appFactory){
contactDetail = appFactory.getContactDetailPresenter();
}


This highlights the high-level capabilities of Gin dependency injection. For the interfaces in the application, we configure the associated implementations. We annotate @Inject where we want Gin to inject dependencies and, at runtime, Gin will provide instances of classes all wired up with their dependencies injected. There are many additional capabilities for additional DI use cases. See this link for more details.



Although we saw the capabilities, we didn’t fully take advantage of them. One of the ideas of dependency injection is that factories need not be a prominent part of the application and we still have a factory sent in to the AppController so that the presenters can be acquired. The final thing we’d do here to take optimally take advantage of the DI capabilities is to have the ContactDetailPresenter and ContactListPresenter injected in to the AppController. Then all the injector needs to do is return an instance of the AppController and everything from the AppController all the way down to the views will be wired up for use.



@GinModules(AppGinModule.class) 
public interface AppInjector extends Ginjector{
public AppInjector getAppController();
}


And the entry point logic can look something like so:



	AppInjector appInjector = GWT.create(AppGinModule.class);
new AppController(appFactory).go(contacts);


With this, our Contact Management application does not create any presenters or views directly and does not managing wiring them up together. This goes a long way to creating loosely-coupled units of the overall application. Aside from that, the Gin framework has an innovative, crisp way of configuring the dependencies.



Testing



In order to get an injector implementation, our code called GWT.create(). GWT.create is a special object-creation utility in the GWT library which heavily depends upon the GWT environment. This means that, in order to create a GIN injector in a JUnit test, the JUnit must extend GWTTestCase and this is a barrier to testability since GWTTestCase is much slower than a “normal” JUnit. This does not have to be a problem as long as we consider it ahead of time. In our Contact Management AppController scenario, we removed “factories”/”injectors” out of most of our application code except the Entry Point. In that case, there really is no issue. At test time, we can wire our dependencies up however we want and we have no strong reliance on GIN in our JUnits. However, this may not be realistic in all applications and we may want to pass an injector in to parts of the application so that the Injector can operate behave more like a factory. An example of this may be a portal where the portal viewing area could display 1 of 20 different types of presenters. It may not be ideal to have GIN initialize/inject all 20 presenters when the application starts in which case, we’d want the portal to create the appropriate presenter as needed. In this case, it would be reasonable to pass an Injector in to the PortalPresenter so a injector/factory is available which can then help the PortalPresenter create the appropriate child-presenters when and if they are needed. In this case, we’ll want a GIN injector implementation that can behave how we want at test time to pass in to the PortalPresenter.



We mentioned earlier that Gin is the GWT-equivalent of Guice and at this time, it’s worth noting that the @Inject annotation we used is actually from the Java Guice library. This means that, outside of a GWT environment, we can use Guice as our DI framework. And since when testing, we do not want to be forced in to a GWT environment, Guice is a good choice to replace Gin at test-time. Guice also has the concept of a Module where we can bind implementations to interfaces and the methods/semantics are nearly comparable. For our Contact Management scenario, it could look like the following:



	public static class MockAppModule extends AbstractModule{

@Override
protected void configure() {
bind(ContactListView.class).toInstance(createNiceMock(ContactListView.class));
bind(ContactDetailView.class).toInstance(createNiceMock(ContactDetailView.class));
}
}


And here’s a tiny utility that will dynamically generate a Gin Injector implementation outside of a GWT context:



	/**
* Builds an implementation of the GinInjector which does not require a GWT runtime environment.
*


* This can be used in a JUnit that does not extend {@link GWTTestCase}.
*
* @param type of application injector to create
* @param guiceModule the Guice module
* @param appInjector type of application injector to create
* @return an implementation of the GinInjector which does not require a GWT runtime environment.
*/
public static T guiceCreate(Module guiceModule, Class appInjector){
Injector guiceInjector = Guice.createInjector(guiceModule);
return getServerSideGinInjector(guiceInjector, appInjector);
}

/**
* This creates the equivalent of a GinInjector without needing to call GWT.create().
* This can be useful for JUnits.
*
*/
public static T getServerSideGinInjector(final Injector injector, Class appInjector){
T result = (T)Proxy.newProxyInstance(Injector.class.getClassLoader(),
new Class[]{appInjector}, new InvocationHandler() {

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Class returnType = method.getReturnType();
return injector.getInstance(returnType);
}
});
return result;
}



Now we can call guiceCreate() and it will create an implementation of the specified Gin Injector interface and it will be configured according the specified Guice module definition.



AppInjector mockAppInjector = guiceCreate(new MockAppModule(), AppInjector.class);
assertNotNull("The controller should be available outside of a GWT environment", mockAppInjector.getAppController());


Usage



GIN is not part of the core GWT library. It is an extension that was created and is well-supported by Google. In order to use it, a few things are needed:



1) GIN must be included in the application by inheriting it in the GWT application XML:



<inherits name="com.google.gwt.inject.Inject"/>



2) The GIN jar must be on the classpath at compile-time and run-time. The Guice and Aop Alliance jars must be on the classpath at compile and test-time.



Summary



In this post, we looked at how and why to use Dependency Injection. In particular, we looked at using GIN to loosely couple the pieces that make up our applications. Additionally, we looked at how to make this approach viable outside of a GWT environment so that we can have a good testing strategy.

4 comments:

  1. good article, but You hava an error:
    instead of this:
    AppInjector appInjector = GWT.create(AppGinModule.class);
    shoud be this:
    AppInjector appInjector = GWT.create(AppInjector.class);

    Cheers from AngloPolish.com:)

    ReplyDelete
  2. Awesome! Helped a lot. Thanks.

    Just one minor point. The signature for guiceCreate is given as:

    public static T guiceCreate(Module guiceModule, Class appInjector)

    It should be:

    public static T guiceCreate(Module guiceModule, Class appInjector)

    and similarly for getServerSideGinInjector

    ReplyDelete
  3. Uggh! The comment tool is swallowing up template characters. Which is probably what happened with the original post as well.

    I meant to say guiceCreate() should be genericized on type T. The class argument should carry the same type argument.

    ReplyDelete
  4. Thanks for such awesome blog. Your article is very easy to understand, informative and provide complete overview about software testing. Please consider including rss feed in your website, so I get your recent post on my site. Best angularjs training in Chennai.

    ReplyDelete

Followers