My application contains a number of basic model types (let's call them Foo, Bar, Baz, Etc). The goal of my application is to manage these Foos and Bars, and so on. My application then performs basic CRUD operations on each of these types, such as "create Foo", "read Foo", "update Foo" and "delete Foo". The same applies to each of the other model types as well.
To handle these events, I've created some custom events: CreateFooEvent, ReadFooEvent, UpdateFooEvent, and DeleteFooEvent. I am finding that each model type then requires four new event types and four new event handler interfaces, which is becoming increasingly redundant. To cut down on clutter, I am really looking for a way to abstract these events, since they are all virtually the same, save for the GwtEvent.Type they contain and return. Despite all my efforts, though, I haven't had much success in abstracting these events. The primary reason is that for a given instance of HandlerManager, you cannot register EventHandlers for two different generic events. Let's take a look at my generic code: public class GenericEvent<T> extends GwtEvent<GenericHandler<T>> { public static Type<GenericHandler<?>> TYPE = new Type<GenericHandler<?>>(); private T resource; public GenericEvent(T resource) { this.resource = resource; } @SuppressWarnings("unchecked") @Override public Type<GenericHandler<T>> getAssociatedType() { return (Type) TYPE; } public T getResource() { return this.resource; } @Override protected void dispatch(GenericHandler<T> handler) { handler.onGenericEvent(this); } } public interface GenericHandler<T> extends EventHandler { void onGenericEvent(GenericEvent<T> event); } Now, let's try adding two GenericHandler<T> instances to our HandlerManager in a unit test that will fail (because both handlers get triggered). public class GenericEventTest { private boolean fired = false; @Test public void genericHandlerRegistrationTest() { HandlerManager manager = new HandlerManager(null); manager.addHandler(GenericEvent.TYPE, new GenericHandler<String>() { @Override public void onGenericEvent(GenericEvent<String> event) { Assert.assertEquals("hello", event.getResource()); GenericEventTest.this.fired = true; } }); manager.addHandler(GenericEvent.TYPE, new GenericHandler<Integer>() { @Override public void onGenericEvent(GenericEvent<Integer> event) { Assert.fail(); } }); manager.fireEvent(new GenericEvent<String>("hello")); Assert.assertTrue(this.fired); } } I spent some time trying to refactor GenericEvent so that it respects the generic type <T> when dealing with the public member TYPE, but all of my efforts have failed. The problem is two-fold: 1) The handler must be registered with an instance of GwtEvent.Type compatible with the generic type the handler is written for, and 2) the event, when fired, must return the same instance of GwtEvent.Type that the intended handlers used to register themselves. My best attempts thus far are: 1) Have GenericEvent maintain a map of classes to types, and then provide a static method for retrieving those types. For various compiler and type safety reasons, though, I cannot make this compile. Below is the ideal code, but it doesn't work, and I have tried nearly permutation of it I can think of. public static <T> Type<GenericHandler<T>> getType(Class<T> clazz) { ... } @Override public Type<GenericHandler<T>> getAssociatedType() { return (Type<GenericHandler<T>>) GenericEvent.getType (this.resource.getClass()); } 2) Store GwtEvent.Type instances outside the GenericEvent (such as on the model class itself) and pass in the desired type when firing the event: public GenericEvent(T resource, Type<GenericHandler<T>> type) { ... } I am not particularly thrilled with the second option for a variety of reasons, but I don't have many other ideas. The alternative, of course, is to continue amassing a collection of [Verb][Noun]Event and [Verb][Noun]Handler classes... Any other suggestions?
-- http://groups.google.com/group/Google-Web-Toolkit-Contributors