GWT RequestFactory with GIN

by Stefan

Creating GWT RequestFactory instances requires a GWT.create() call. These calls should be outside of your classes under test, as GWT.create() internally invokes native JavaScript code. This causes a ExceptionInInitializerError when run as a plain JUnit test.

A very elegant solution is to use Dependency Injection with GIN and let the framework create and assemble both the RequestFactory and corresponding RequestContext instances. In general, using DI is a good idea for all layers of business application, and GIN brings the well-known concepts of Guice into the GWT world.

Here’s an example with a PizzaService in the backend and the corresponding RequestFactory setup:

public class PizzaService {
  public void orderPizza( String name ) {
    // back-end business logic comes here
  }
}
import com.google.web.bindery.requestfactory.shared.Request;
import com.google.web.bindery.requestfactory.shared.RequestContext;
import com.google.web.bindery.requestfactory.shared.RequestFactory;
import com.google.web.bindery.requestfactory.shared.Service;

public interface PizzaRequestFactory extends RequestFactory {

  @Service(PizzaService.class)
  public interface PizzaRequestContext extends RequestContext {
    public Request<Void> orderPizza( String name );
  }

  public PizzaRequestContext context();
}

GIN requires us to setup a GinModule and an Ginjector interface. The module defines the container for all managed beans (like Spring’s ApplicationContext). Beans can either be registered in the configure() method or a separate method annotated with @Provides can be used (kind of BeanFactory). Here’s all code to make the PizzaRequestFactory and its context available in the local GinModule:

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.event.shared.SimpleEventBus;
import com.google.gwt.inject.client.AbstractGinModule;
import com.google.gwt.inject.client.Ginjector;
import com.google.inject.Provides;
import com.google.inject.Singleton;

public interface PizzaGinjector extends Ginjector {

  public class PizzaGinModule extends AbstractGinModule {

    @Override
    protected void configure() {
      bind( EventBus.class ).to( SimpleEventBus.class );

      bind( PizzaClient.class );
    }

    @Provides
    @Singleton
    public PizzaRequestFactory createPizzaRequestFactory( EventBus eventBus ) {
      PizzaRequestFactory factory = GWT.create( PizzaRequestFactory.class );
      factory.initialize( eventBus );
      return factory;
    }

    @Provides
    public PizzaRequestContext createPizzaRequestContext( PizzaRequestFactory factory ) {
      return factory.context();
    }
  }
}

The PizzaRequestFactory is only created once due to the @Singleton annotation. An EventBus instance is automatically injected. The same applies for the second method where the PizzaRequestFactory is passed to create a PizzaRequestContext. As a GWT RequestContext holds a state, a new instance is returned on every request.

How can consumers aquire the RequestFactory classes created by GIN? Simply by adding an @Inject to the constructor (note that this is Googles’s com.google.inject.Inject and not javax.inject.Inject annotation):

import cleancodematters.PizzaRequestFactory.PizzaRequestContext;

import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.web.bindery.requestfactory.shared.Receiver;

public class PizzaClient {
  private final Provider<PizzaRequestContext> contextProvider;

  @Inject
  public PizzaClient( Provider<PizzaRequestContext> contextProvider ) {
    this.contextProvider = contextProvider;
  }

  public void orderPizza( String name, Receiver<Void> receiver ) {
    contextProvider.get().orderPizza( name ).fire( receiver );
  }
}

In this example we don’t aquire PizzaRequestContext directly (although that’s of course possible, too) but use the Provider interface. This allows us to create the context on demand by calling Provider#get(). This is especially useful if the creation of the requested class should be defered (e.g. for Views that create widgets). In the context of RequestFactories this makes sense as the same RequestContext instance must be used for editing and submitting to the server. Here’s a snippet that modifies a pizza entity and sends it over the wire:

  public void updatePizzaName( PizzaProxy pizza, String newName ) {
    PizzaRequestContext context = contextProvider.get();
    // Get context and create editable proxy
    PizzaProxy editablePizza = context.edit( pizza );
    editablePizza.setName( newName );
    // Use same context for firing the request
    context.modifyPizza( editablePizza ).fire();
  }
Advertisements

4 Comments to “GWT RequestFactory with GIN”

  1. Does it really work? I’m not sure you can use @Provides in such context. Check this out: http://code.google.com/p/google-gin/wiki/GinFaq#What_bindings_don't_work?
    So you shouldn’t be able to do factory.initialize( eventBus );

    I’ve tried but I’m getting error

  2. Thank for your post, is very useful and well done

  3. Nice. However what should be done in case of a big object graph with lots of different RequestContexts? Of course I could create for each of them a Provider. But is there somehow a more elegant solution to create a generic provider maybe by using Generics?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: