• Home
  • Events
  • About
  • Code generation in GWT with Deferred Binding (CDI-like events)

    If you read my series on GWT dependency injection (parts: first, second and third), maybe you remember that, in part 3, I mentioned how convenient would be to reduce the boilerplate required to define events in GWT. I also mentioned how elegant I find the event definition in CDI. Wouldn’t it be nice to have a lightweight event model like that in GWT?

    Let’s see first how an event is defined and handled in CDI:

    As you can grasp from the code, to define a new type of event in CDI it is enough to define an injected field of the parametrized class Event and the CDI container will do all the wiring for us. The parametrized type of the event defines its payload type by mean of the type parameter. To listen to the event, we just need to define a method that receives a parameter of the event payload type and annotate it with “@Observes”.

    While exactly this is maybe not doable in GWT (at least not yet), what about something like this?:

    While I can agree with you that it is not as elegant as the events approach in CDI, it is (IMO) a big improvement compared with, for instance, the ping / pong event definition in the demo application of my GIN series (source code here):

    With the new approach, the resulting “PingEvent” would look like this:

    If you are wondering why not to avoid defining the “PingEvent” class itself, two are the reasons:

    • First, the events have the same payload type (Void in this case), and therefore we need explicit types to distinguish the ping event from the pong event. This also happens in CDI where we would define explicit payload types instead.
    • Second, in this implementation we will be using GWT’s deferred binding and, during the code generation phase, we need to know the parametrized type. Because of Java generics limitations, for this last it is necessary to define a new parametrized type which captures the payload type in its type parameter (wrapper).

    Did I convince you? If I did, let’s go on and see how to use deferred binding and dependency injection to achieve it.

    Letting GWT generate the boilerplate

    Deferred binding in GWT is a really powerful feature implemented in the GWT compiler to substitute class implementations depending in environment properties like the user agent. This way, while the developer has the illusion of using the same classes independently of the browser, the deferred binding mechanism allows to select the adequate implementation for each browser.

    Far from being static, deferred binding allows to generate code on the fly by mean of a generator class. This happens when the developer invokes the “GWT.create()” method on an interface. For the operation to succeed, a generator for the interface must exist. This will be invoked during GWT compilation time and its result (one or more Java classes) will be compiled and linked into the resulting JS application.

    To configure which generator should be used for which interface, it is necessary to add a new “generate-with” entry in the GWT module descriptor. In the case of the demo application, the following code has been added to the “PingPong.gwt.xml” file:

    The contents of the “Event” and “EventGenerator” classes are the following:

    While the “Event” class contains the interface definition for our events and lives in the “client” package of our GWT application, the “EventGenerator” is a GWT specific class that resides in the “server” package of our GWT application. In order to compile the code, we will need to add a new dependency to our project: “gwt-dev-<version>.jar”.

    This generator class, by mean of some templates included in the source code, generates the boilerplate classes and saves us the tedious work of writing these classes. If you want to see this in detail, please refer to the “eventsfwk” packages in the client and server part of the application (source code here).

    Using GIN to bring everything together

    Following what I mentioned until now, it seems that if we define an interface extending the “Event” interface (ex: “SampleEvent”) and we use the generator to generate and wire the code by mean of “GWT.create(SampleEvent.class)”, we should be able to use the result as shown in the “GWTSample” execute method. Not really.

    One piece that is missing in the puzzle is which event bus should the underlying GWT events use. We could create an own one without loosing functionality but a better thing that we can do is to provide an injection point and provide a mechanism to make our events participate in the application’s dependency injection context and use the application’s event bus instead of an own instance.

    To achieve this, we have created a GIN module in the “eventsfwk” package:

    This module should be installed in the application’s dependency context and it will inject an static field in the “GwtSimpleEvent” class which is the event bus used for our improved events. To install it in our application, the injection module has been modified like this (note the line “install(EventsModule.class);”):

    This means that, when the dependency injection module is initialized at the beginning of the application execution, the previously configured event bus will be statically injected in the “GwtSimpleEvent” class used by all the generated event classes.

    I can not read minds, but maybe you are also wondering why the event fields annotated with “@Inject” get generated and injected. All in all, we don’t call anywhere “GWT.create()” to use the generator class.

    Well, we are not doing it but GIN does. Whenever GIN finds a dependency (something annotated with “@Inject”) and that dependency has not explicitly been configured (bound in the GIN modules), GIN invokes “GWT.create()” as fallback strategy. This simple mechanism allows us to generate and inject our event in only one step.

    Wow! This post has been “hardcore” GWT, don’t you think? Maybe even too “hardcore”. Please, just let me know if you like it and what do you think about the approach.

    See you in a future post!

    The source code for the initial version of the application can be downloaded here. The final version here. To see any of the applications working, unzip the corresponding 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.

    Share and Enjoy: These icons link to social bookmarking sites where readers can share and discover new web pages.
    • DZone
    • Y!GG
    • Webnews
    • Digg
    • del.icio.us
    • DotNetKicks
    • Facebook
    • Google Bookmarks
    • Newsrider
    • Twitter
    • YahooBuzz

    5 Comments »

    1. uboness said,

      July 4, 2011 @ 15:25

      GWToolbox provides both DI and internal event bus support out of the box:

      @Component
      public class MyWidget extends Composite {

      private final Service service;
      private final Label label;

      @Inject
      public MyWidget(Service service) {
      this.service = service;
      label = new Label();
      initWidget(label);
      }

      @EventHandler
      public void handle(MessageEvent event) {
      label.setText(event.message());
      }

      }

    2. Kai Wähner said,

      July 4, 2011 @ 18:58

      Awesome blog! I like the approach…

      Nevertheless, as you already suspect: IMHO it is tooooo hardcore for an average GWT project.

      I even think that several GWT additions in the last releases (such as integrated MVP or Activities and Places) make many projects too complex. These features are not bad, but the complexity of such a project increases a lot.

      Best regards,
      Kai Wähner (Twitter: @KaiWaehner)

    3. Alberto said,

      July 5, 2011 @ 8:37

      @uboness: GWToolbox looks interesting but, is its IoC container based on GIN?
      It seems that GIN is the “de facto” IoC in GWT and I thought that extending the GIN container by mean of an extension (this seems to be still on the works) would be the best approach.

      Thanks!
      Berto

    4. krkr said,

      July 16, 2011 @ 22:33

      I recommend guit : http://code.google.com/p/guit/wiki/GuitBinder !

      @EventBusHandler
      public void $login(String user) {

      }

      to bind with this event:

      @GwtEvent(EventKind.SHARED)
      public class Login {
      String user;
      }

    5. Stephen said,

      July 17, 2011 @ 3:38

      Cool approach. I agree GWT event definitions are too verbose.

      I think SampleEvent is somewhat misnamed; with events, there is typically a new event instance each time you call fire. It looks like in your example, there are multiple payload instances, but only one “SampleEvent” instance. So I’d be tempted to call it a “SampleEventDispatcher” or something like that.

      I have my own take on simple event declarations:

      https://github.com/stephenh/gwt-mpv-apt

      It uses an annotation processor instead of deferred binding, so doesn’t rely on GWT.create, and so, IMO, is more amenable to unit testing since you don’t need dev/web mode running.

      It ends up looking like:

      @GenEvent
      class PingEventSpec {
      @Param(1)
      String payload;
      }

      And it generates PingEvent with the standard TYPE, handler, etc., boilerplate.

    RSS feed for comments on this post · TrackBack URI

    Leave a Comment


    five × = 5

    css.php