Google Gin

Barman ! Un gin s’il vous plaît ! Gin Fizz ? Gin Tonic ? Non… Google Gin.
Pour ceux qui se demandent ce que signifie ce nom, Gin vient de GWT INjection. C’est le pendant de Guice, framework d’injection de dépendance également développé par Google, mais cette fois pour la partie cliente GWT. L’injection de dépendance en Javascript, vous en rêviez, Google l’a fait.

L’intérêt

Avant de détailler comment mettre en place GIN, nous allons voir à quelles fins nous pouvons l’utiliser. Tout d’abord, ne cherchez pas l’intérêt de Gin du côté de la performance. Le code généré en utilisant Gin sera équivalent à un code développé de façon classique (Il ne faut pas oublier que tout le code écrit en Java (côté client GWT) est transformé et optimisé par le compilateur GWT pour donner au final du code Javascript).
L’intérêt principal réside dans la simplification du code et sa lisibilité. En utilisant l’injection de dépendance, vous n’avez plus besoin de garder des références static de partout pour accéder à vos services ou vos objets. Imaginez pouvoir accéder à votre EventBus ou votre Bundle d’images en ajoutant simplement l’annotation @Inject, et là la magie opère.
Utiliser Gin va également vous permettre de mettre en place une politique précise d’instanciation de vos objets. Cette politique correspond au binding que vous déclarez dans la configuration du module Gin, nous verrons cela après.
Pour en revenir au côté simplification du code, l’injection automatique mais aussi l’instanciation automatique de tous les dictionnaires, les bundles d’images et les services RPC (Remote Procedure Call) est une facilité à laquelle on devient vite accros.

Mise en place

Maitenant, mettons un peu les mains dans le cambouis. La mise en place de Google Gin est extrêmement simple et bien documentée.
Avant tout, il faut importer le module GIN. Pour cela, nous allons le déclarer dans le fichier de configuration de notre application GWT à l’aide de la balise inherits :

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

Ensuite, déclarer une interface qui hérite de Ginjector (Prononcez “Gin-jector” et non “G-Injector”) qui doit définir des méthodes avec des types de retour correspondant aux types désirés. Seuls les objets que vous souhaitez récupérer depuis l’instance de l’injecteur doivent être ajoutées dans cette interface. Les objects injectés automatiquement via l’annotation @Inject par exemple, n’ont pas besoin d’être déclarés. En d’autres mots, comme le dit la documentation, “Les méthodes de l’injecteur fournissent un pont entre le monde Gin et le monde non-Gin”.

public interface ZenGinjector extends Ginjector {
  MainPanel getMainPanel();
}

La prochaine étape est de déclarer le binding. Dans l’exemple suivant, nous allons binder la classe MainPanel en tant que Singleton tandis que la classe ZenRemoteService est bindé sur un Provider, ZenRemoteServiceProvider. Le binding définit comment seront instanciés les objets en question. Par exemple, lorsque vous utiliserez l’injecteur pour MainPanel, la même instance vous sera toujours renvoyé, puisque le scope est “Singleton”

public class ZenClientModule extends AbstractGinModule {
  protected void configure() {
    bind(MainPanel.class).in(Singleton.class);
    bind(ZenRemoteService.class).toProvider(ZenRemoteServiceProvider.class);
  }
}

Il faut par la suite lier le module avec l’injecteur en utilisant l’annotation @GinModules.

@GinModules(ZenClientModule.class)
public interface ZenGinjector extends Ginjector {
  MainPanel getMainPanel();
}

Finalement, une fois que toutes les classes et interfaces pour définir l’injecteur sont prêtes, il ne vous reste plus qu’à instancier celui-ci, et pour cela rien de mieux que la bonne vieille méthode GWT.create(…) et ensuite récupérer les objets que l’on souhaite en appelant les méthodes définies sur l’injecteur.

public class ZenGinExample implements EntryPoint {
  private final ZenGinjector injector = GWT.create(ZenGinjector.class);
  public void onModuleLoad() {
    MainPanel mainPanel = injector.getMainPanel();
    RootPanel.get().add(mainPanel);
  }
}

Pour rappeler ce qui a été dit précédemment, vous n’avez besoin de l’injecteur que pour faire le pont Gin/Non-GIN, récupérer les objets dont vous aurez besoin via les méthodes de l’injecteur
. Pour les autres objets, vous pouvez utiliser l’injection classique de Guice, comme dans l’exemple suivant, via annotations.

public class ZenWidget {
  @Inject
  public ZenWidget(MyRemoteServiceAsync service) {
  ...
  }
}

Il est intéressant de noter qu’il n’est pas nécessaire de déclarer de binding pour les objets qui sont créés via la méthode GWT.create(…), tels que les dictionnaires d’i18n, les bundles d’images ou de css ou encore les services RPC de GWT, car lorsque Gin ne trouve pas de binding, il utilise en fallback GWT.create(…)

Les différences avec Guice

La première différence entre Gin et Guice est le nom des interfaces. En Gin, celles-ci s’appellent Ginjector, GinModule et AbstractGinModule tandis qu’avec Guice, elles se nomment Injector, Module et AbstractModule.
La seconde est que Gin ne possède qu’un sous-ensemble de fonctionnalités de Guice. Pour vous rendre compte, Gin fournit un tableau comparatif entre les différentes versions de Gin et de Guice : Guice Compatibility
Enfin, si vous souhaitez réutiliser le code écrit avec Gin, dans Guice, un adapteur est fourni, GinModuleAdapter qui vous permet par exemple de partager du code entre le client et le serveur (J’avoue personnellement ne voir qu’un intérêt limité à cette fonctionnalité mais qui sait… mieux vaut en avoir trop que pas assez)

Conclusion

Pour conclure et vous donner mon avis, utilisez Gin. Pour l’instant il n’existe pas d’équivalent pour la partie cliente de GWT, et le coût de mise en place est négligeable comparé au gain que vous pourrez en retirer, à la fois en terme de productivité mais aussi de maintenabilité de code.
Le lien du projet : http://code.google.com/p/google-gin/

Laisser un commentaire

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.

%d blogueurs aiment cette page :