GWT Dependency Injection recipes using GIN (III)
June 20th, 2011This is the third part of a series about Dependency Injection in Google Web Toolkit using GIN. If you have not yet read the first and second parts, you maybe should do it before reading this third and last article.
In this article, we will introduce two GIN features: “constants binding” and “static injection”.
To do this with an example, let’s refactor the “serve button” in the “Simulator” main class of the second part into an own class:
...
final Button button = new Button("Serve!");
button.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
button.setVisible(false);
injector.getRacket().serve();
}
});
...
Here the new extracted “ServeView” class:
public class ServeView extends Button {
@Inject
public ServeView(final Racket racket, @Named("ServeText") String serveText) {
super(serveText);
addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
setVisible(false);
racket.serve();
}
});
}
}
As you can see, the constructor of this new class is annotated with the “@Inject” annotation and receives two parameters. One of them is the racket and the other is the button’s label. In the case of the racket, it is already defined as an injectable dependency in the injector interface and in the case of the button’s label, it should be a configurable constant.
GIN, by mean of “constants binding”, performs the binding of injectable dependencies to constants.
Because the type of the “serveText” is String, we need to be more specific here and therefore we have annotated this dependency with the “@Named” annotation. To configure the constant value to bind to, we need to add the following line into our “InjectorModule” class:
...
bindConstant().annotatedWith(named("ServeText")).to("Serve!");
...
To let the other constants in the application be configured in the same way and to introduce the last GIN feature (“static injection”), let’s now modify the “Simulator” main class as follows:
public class Simulator implements EntryPoint {
@Inject
static ServeView SERVE_VIEW;
@Inject
static AssistedInjectionFactory FACTORY;
@Inject
@Named("PingText")
static String PING_TEXT;
@Inject
@Named("PongText")
static String PONG_TEXT;
public void onModuleLoad() {
initInjection();
RootPanel.get("buttonSlot").add(SERVE_VIEW);
RootPanel.get("pingSlot").add(FACTORY.createPingPongView(PING_TEXT, PingEvent.class));
RootPanel.get("pongSlot").add(FACTORY.createPingPongView(PONG_TEXT, PongEvent.class));
}
private void initInjection() {
GWT.create(Injector.class);
}
}
And our “InjectorModule” like this:
public class InjectorModule extends AbstractGinModule {
@Override
protected void configure() {
bind(EventBus.class).to(SimpleEventBus.class).in(Singleton.class);
install(new GinFactoryModuleBuilder().build(AssistedInjectionFactory.class));
bindConstant().annotatedWith(named("PingText")).to("Ping");
bindConstant().annotatedWith(named("PongText")).to("Pong");
bindConstant().annotatedWith(named("ServeText")).to("Serve!");
requestStaticInjection(Simulator.class);
}
}
The “static injection” allows us to inject the static fields of a class. This happens by mean of the method “requestStaticInjection” of the GIN module class and, in our application, we use it to inject the static dependencies of the “Simulator” class.
This way, even when the “Simulator” class does not participate in the dependency injection context, its static members will be injected making the explicit references to the injector not required.
This has the side-effect of making the “Injector” getters no more necessary leaving our injector interface “empty”:
@GinModules(InjectorModule.class)
public interface Injector extends Ginjector {
}
Please note that, in order to get the dependency injection context configured and initialized, it is required to instantiate the “Injector” interface by mean of the “GWT.create()” method as part of the application initialization. This is done in our case within the “initInjection” method in the “Simulator” main class.
Conclusions
If you have read the 3 articles of this series, maybe you can remember how our demo application looked like at the beginning. While the functionality and appearance has not changed at all, the intern structure of the application is completely different.
In my opinion, dependency injection allows a much cleaner structure, enables configuring the application in an elegant and easy way and, when used together with an event bus, produces low-coupled high-modular applications.
Of course, “there is no free lunch” and using GIN means also that the development team has to learn new concepts and introduce a new framework in the application. Anyway, dependency injection is an already proven concept and GIN is being intensively used in most of the new GWT projects and GWT frameworks.
While some minimal application structure optimizations could still be applied to the application, the thing that I still find improvable in it is the verbosity of the GWT events definitions. This requires writing some boilerplate classes to ensure the type safety (event handlers), and also the definition of the own event classes is too verbose, being possible to generate them automatically in most of the cases by using either GWT’s deferred binding or a JDK 6 annotation processor. If you know how the events in CDI are defined, very probably you will agree with me that such an approach would be much more elegant and concise.
A solution for that, even when it requires dependency injection, is more related to other topics and therefore a subject for a different thread. If you got curious, stay tuned for a future post on code generation in GWT!
The source code of the application can be downloaded here. To see the application working, unzip the file, change to the folder where the Maven pom file is stored and type the command: “mvn clean gwt:run”. After the GWT “Development mode” application starts, click on the “Launch Default Browser” button.
As always, I hope that you enjoyed reading this series of articles as much as I did writing it and hope to see you soon in a future post!
Posted by alberto

