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

Reply via email to