Open GoogleCodeExporter opened 9 years ago
What do you think about that?
The event, maybe an abstract class so it extends GwtEvent and can be used
outside GWTP:
public interface MyEvent extends EventBase {
public Thing getThing();
public String getName();
public boolean isRemoved();
}
The handler:
public interface Handler implements EventHandler {
public void onMyEvent(MyEvent event);
}
An interface to send event with some magical stuff:
public interface Sender implements EventSender<MyEvent> {
// Create the event, fill its member with parameters and send it
public void fire(HasEventBus target, Thing thing, String name, boolean removed);
// Create the event but some member will not be set: thing will be null
// The removed member will be set using the annotation
@BooleanParam("removed", true)
public void fireRemoved(HasEventBus target, String name)
}
The sender can be used like that:
GWT.create(Sender.class).fire(....);
Do you like it? I need more input...
Original comment by olivier....@free.fr
on 20 Jul 2010 at 8:44
I like it quite a bit! Although you probably need a way to define a static
field somewhere for the event type, otherwise I don't see how you can register
towards a specific event?
Would it be possible to simplify even more for events that wrap up exactly one
type of object. For example:
// Provided by GWTP:
public interface GenericEvent<T> {
public T get();
}
public interface GenericHandler<T> extends EventHandler {
public void onGenericEvent(GenericEvent<T> event);
}
public interface GenericEventSenter<T> extends EventSender<GenericEvent<T>> {
public void fire(HasEventBus target, T object);
}
// Provided by the User:
public interface UserModifiedSender extends GenericEventSender<User> {
public static Type<GenericEvent<User>> USER_MODIFIED_EVENT = new Type<GenericEvent<User>>();
}
And to create UserModifiedSender we could use Gin injection, maybe? It would be
even cleaner than a GWT.create(...) and we really only need these to be
singletons.
Original comment by philippe.beaudoin
on 20 Jul 2010 at 9:03
I like that ! I only have one question, what if I had more than one object
wrapped inside my event ?
I know that in those case I should create them myself, but it would be awesome
if we could do it !
Original comment by goudreau...@gmail.com
on 20 Jul 2010 at 10:57
In this case, Monaco's way would do it. I was just suggesting we provide a
shortcut for single object events.
Original comment by philippe.beaudoin
on 20 Jul 2010 at 11:15
That whould be great to have both in that case.
Original comment by goudreau...@gmail.com
on 20 Jul 2010 at 11:24
What if instead of gwt-generators, we were use java apt (annotation
processing).
Then we could get rid of both the event/handler boilerplate and the
action/result boilerplate.
Like gwt-mpv-apt, but simpler code that doesn't depend on unreleased libraries.
Original comment by brendanp...@gmail.com
on 21 Jul 2010 at 2:23
Here is @GenEvent working using apt.
http://code.google.com/r/brendanpdoherty-apt/source/detail?r=c8e7856028ae81dee89
9a5d3f282957eafc5e537
Two annotations, @GenEvent says take this class and make an event and a
handler. @Order allows you to specify the order of fields (otherwise they are
alphabetical order). @Order only really shows itself in the constructor. And
not needed if only one field.
@GenEvent
public class My {
@Order(0) Thing thing;
@Order(1) String name;
@Order(2) boolean removed;
}
Will generate the same event/handler as described in comment #1.
Original comment by brendanp...@gmail.com
on 21 Jul 2010 at 12:51
Do you produce a static .fire method ?
And a HasXXXHandlers ?
Also, I was wondering if those custom event where UiBinder ready... Just a
though since not every events needs to be UiBinder ready
Is just that if Eclipse don't know the type of event before compile time it's
kinda hard to write :
@UiHandler("CustomUiWidgetYouMadeName")
void onUnitChange(UnitChangeEvent event) {
}
Same thing goes for listening to an handler.
Am I totally thinking wrong by saying this ?
Original comment by goudreau...@gmail.com
on 21 Jul 2010 at 1:00
@Phil:
So, we have 2 type of events:
- specific (my case)
- generic (your case)
A specific event will have only one Type value. So we can hide it by providing
a addHandler(HandlerManager, Handler) method on the Sender. This allow the
automatically generate the static field in the way GWT do (null by default, not
null only once an handler has registered an handler...).
The generic event is, in fact, an event like ValueChangeEvent: it has a value
typed by generics. Maybe this case must be handled with somethink like your
@ProxyEvent annotation and the discussion we had about it. Because we may want
to be able to use a generic event (not a generated class) but call a specific
on* method linked to a specific Type. Here is an example:
interface MyHandler {
public static final Type<...> DELETE - new ...;
public static final Type<...> CREATE - new ...;
@EventType("DELETE")
onDelete(ValueEvent<Item> event);
@EventType("CREATE")
onCreate(ValueEvent<Item> event);
}
@brendanpdoherty:
I prefere generators. I don't like two step compilation: one before writing
code to generate some code and one after for the real compilation. Of course,
Eclipse do it automatically but I use maven. And all automatic code generation
I used was complicated to configure with Maven, Ant, in complex build or for
continious integration. But if people like that, ok.
Original comment by olivier....@free.fr
on 21 Jul 2010 at 3:14
@christian
From what I understand, apt generates new classes as a precompilation process.
These classes are free to contain new methods, static methods or anything you
like.
@brendan
I think we should strive to handle as much stuff as possible via GWT
generators. I believe you can generate more sensible error messages and you
don't have to worry about things like @Order(...). That being said, I think we
should strive to make sure gwt-mvp-apt remains compatible with GWTP for those
who prefer this approach, and because it's the only method I can see (short of
SpringRoo ;)) for generating dispatcher boilerplate.
@olivier
Your case is more "generic" than mine, so I would say:
- customizable (your case)
- single-object (my case)
In fact, I would implement the single-object case as a specialization of the
customizable case. I like the "ValueEvent" name.
Re: addHandler
The "addHandler" method would be in the EventSender interface? So you would
inject (or GWT.create) a MyEventSender in any object that wants to listen to
the event? I think it's a good idea... However we might want to revisit the
name "EventSender" in that case since it's meant to both fire and listen to the
event. What about EventConnector? (i.e. a "plug" to connect the event into a
bus.
Re: Custom method names
Ok. Let me try to write two scenarios here.
1) The user wants many custom onXXX methods:
// The user would write:
interface ItemHandler extends EventHandler {
public static final Type<ValueEvent<Item>> DELETE = new ...;
public static final Type<ValueEvent<Item>> CREATE = new ...;
@EventType("DELETE")
public void onDelete(ValueEvent<Item> event);
@EventType("CREATE")
public void onCreate(ValueEvent<Item> event);
}
interface ItemConnector extends ValueEventConnector<Item, ItemHandler> { }
// In GWTP we have:
interface ValueEventConnector< T, H extends EventHandler > {
public void fire(HasEventBus target, T content);
public void addHandler(HasEventBus target, Type<ValueEvent<T>> type, H handler);
}
2) The user is fine with a onValueEvent() method:
// The user would write:
interface ItemChangedConnector extends ValueEventConnector<Item,
ValueHandler<Item>> { }
// In GWTP we have:
interface ValueHandler<T> extends EventHandler {
public void onValueEvent(ValueEvent<T> event); // Maybe onValueChanged?
}
Original comment by philippe.beaudoin
on 21 Jul 2010 at 5:30
@Phil
I'm happy to use gwt-generators for events if that works better.
The main reason I was investigating it was to find a better way of generating
the dispatch boiler plate (but look at events first, because it seemed simpler).
If the concepts i've used were to make into mainline for generating dispatch
boilerplate, in eclipse all you need to do is choose to enable annotation
processing and select the gwtp jar.
I'd much prefer to have it in gwtp rather than depend on gwt-mvp-apt, which
seems much more complex than it needs to be, and depends on libraries that I
don't think are released.
@olivier
Wont you have the same problem of pre and post compiling using either
gwt-generators or java annotation processing? I'm interested to know how it
will work better with gwt-generators.
Perhaps http://mojo.codehaus.org/apt-maven-plugin/ will help?
@christian
Given the class below, you get this output:
http://code.google.com/r/brendanpdoherty-apt2/source/browse/samples/MoooEvent.ja
va
@GenEvent
public class Mooo {
@Order(0) int apple;
@Order(4) int bob;
boolean cats;
@Order(3) String[] banana;
}
Original comment by brendanp...@gmail.com
on 21 Jul 2010 at 6:20
Some comments with issue 145, we'll be trying to be more Gwt-Like and remove
eventBus from events.
This line:
public static void fire(EventBus eventBus, int apple, java.lang.String[]
banana, int bob, boolean cats) {
would become:
public static <T extends HasEventHandler> void fire(T source, int apple,
java.lang.String[] banana, int bob, boolean cats) {
You could use HasHandlers instead in the meanwhile we implement HasEventHandler.
As for the output that's hell of a nice way to avoid boiler plate code !
Original comment by goudreau...@gmail.com
on 21 Jul 2010 at 6:29
Christian, I've commented in Issue 145 so as not to detract the thread here.
Let's discuss it there.
Original comment by philippe.beaudoin
on 21 Jul 2010 at 6:38
@brendan
With apt, I write a class (eg My) and it generates a new class (eg MyEvent). I
need MyEvent to write my code so I have to generate MyEvent from My before
writing my code. This is the first step. The second, the real compilation,
takes place after I wrote my code.
Using Eclipse it's seem natural because Eclipse build continually. But if you
write code without Eclipse, you have to run the two pass. And when you change
My, you must think to re-run the generation. It's a good way, for me, to commit
bugs ("oops, I forgot the test my code with the new generated MyEvent before
committing").
With generator, your code must compile before the generation takes place. Of
course, this means you generate the code each time you compile. But your code
is always well-formed for the compiler.
So, generators seems even more magic then apt ;).
Original comment by olivier....@free.fr
on 21 Jul 2010 at 8:52
I still don't get difference between apt and gwt-generators, but I'd like to
understand it, as it's the only method for generating dispatch boilerplate (gwt
generators wont be able to do it).
Am i correct that both apt and gwt-generator need to run at compile time?
Is the problem that maven is not automatically running apt, but maven is
automatically running the gwt-generator?
Would the problem be solved by using apt-maven-plugin and adding the following
xml to your pom?
<project>
...
<build>
...
<plugins>
...
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>apt-maven-plugin</artifactId>
<version>1.0-alpha-3</version>
<configuration>
<factory>com.gwtplatform.annotation.processor.GenDispatchAptFactory</factory>
</configuration>
<dependencies>
<dependency>
<groupId>com.acme</groupId>
<artifactId>com.gwtplatform</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</plugin>
...
</plugins>
...
</build>
...
</project>
Original comment by brendanp...@gmail.com
on 21 Jul 2010 at 10:11
@brendan
We must continue our discussion here:
http://groups.google.com/group/gwt-platform/browse_frm/thread/c15c7991c25c9776
Original comment by olivier....@free.fr
on 21 Jul 2010 at 10:28
I'm lost ;)... Let me try to merge all ideas.
First we need an event. The event class can be:
(1) A single-object/generic event. This event, ValuedEvent<T>, is an
"hard-coded" event class (not generated). The only problem is the "dispath"
method but we will see it later.
(2) A customizable/specific event. The developer must define an abstract class
extending GwtEvent, to keep us in the GWT-way. All abstract methods of this
class must be getters and will be the data members of this event.
public abstract class MyEvent extends GwtEvent<...> {
public abstract Thing getThing();
public abstract String getName();
}
Next, we need an handler and a type. One type for one handler method.
(3) We can use the same way as GWT. But one event will have only one type and
so one handler method. I don't like that
(4) We can link the type with the handler. For simple handler, the developer
define the following class (XXX for any name, can be all different):
public interface MySimpleHandler {
public static final Type<...> XXX = ...;
public void onXXX(XXXEvent event);
}
For handler with multiple possible method for one event, we can use names:
public interface MyComplexHandler {
public static final Type<...> YYY = ... ;
public static final Type<...> ZZZ = ... ;
@EventType("ZZZ")
public void onUUU(XXXEvent event);
@EventType("YYY")
public void onVVV(XXXEvent event);
}
With this approach, the dispath method of the event can be implemented using
many ways. We can link each event with one handler. This is not good because we
can do (1) and the developer can't reuse events of (2). The best is to use a
dispatcher to call the good handler method. This dispatcher is included in the
event and used by the dispath method.
This approach allow us to forget the addHandler because each event type can be
directly accessed by the developer to register handlers.
Now how to send an event?
(5) To send a ValuedEvent (1), we can include the following method in the event
class:
public static void fire(HasHandlers source, Type<...> type, T value);
(6) To send a customizable event (2), we need a sender. So, the developer
define it like that:
public interface MySender {
public void fire(HasHandlers source, Type<...> type, ...);
}
The final "..." are each member of MyEvent. And we can include all stuff I told
in comment #1.
What do you think? Do I forgot something?
Original comment by olivier....@free.fr
on 21 Jul 2010 at 10:29
It's not good. The event can't link a type to an handler method. We need some
code generation.
Maybe, (1) must be an abstract class with the dispatch method not implemented.
The developer must create it's own class to link ValuedEvent to an handler:
public abstract class MyEvent extends ValuedEvent<Thing, MyHandler> {}
The problem is we need also a sender (6) for ValuedEvent. The (5) can't now be
done.
For (2), the event must be linked to an handler (it's the "..." of GwtEvent):
public abstract class MyEvent extends GwtEvent<...> {
public abstract Thing getThing();
public abstract String getName();
}
However, we can't now reuse events.
Original comment by olivier....@free.fr
on 21 Jul 2010 at 10:46
Actually, Brandan's way create the class in a real usable file... rendering
them visible for you to use in your code directly ! And that's what I like
about it the most !
Original comment by goudreau...@gmail.com
on 21 Jul 2010 at 10:52
Oh and in the generated event, there was a static fire method !
Original comment by goudreau...@gmail.com
on 21 Jul 2010 at 10:53
I'm stupid, the sender is the dispatcher... I forgot that ;).
So (1) must use a sender, (5) can't be used. In my code sample for MySender, I
forgot the "extends...":
public interface MySender extends Sender<MyHandler> {...}
The sender is generated "using" Gin (as a singleton). When a fire method is
called. The sender create the event, sets the data members and the type, add
itself as the dispatcher and fire the event to source.
The dispath method of the event call a dispath (default-visible) method which
choose the right method depending on the type.
So we can do (1), (2) and (4) as-is. (3) is to avoid. (5) can't be done. (6)
must follow this comment.
Original comment by olivier....@free.fr
on 21 Jul 2010 at 10:53
Instead of a Sender we could have a Connector that would have both a .fire()
and a .addHandler() method. See Comment 10 above for details on how I would do
this.
In this case, the type doesn't have to be provided by the user (unless he wants
to use type-injected event. That is, a single event class with different event
types, which we could support also).
I will be away for the next 2 weeks, but this issue is a priority for me, so if
you want to start working on it, go ahead!
Original comment by philippe.beaudoin
on 23 Jul 2010 at 10:46
Original comment by olivier....@free.fr
on 27 Jul 2010 at 3:31
I've done a little and minimalist prototype.
http://codereview.appspot.com/1942045
Currently I've only done generators for the event and for an interface I
currently calling Sender. Now there is many things possibles.
1) I've choose to define a @EventClass annotation. So one sender can send many
different events. Is it a good choice?
2) Currently, the Sender interface have only fire methods. I've choose to use
HasHandlers (and not EventBus or HasEventBus) so this code can be used with
standard events. Is it ok?
3) If the Sender interface use HasHandler, it can't include an addHandler
method. A such method needs a HandlerManager (or access to protected methods
like the one in Widget class). That's why it's not a Connector for instance.
4) The type is currently defined on the event class. Maybe we can remove this
need and require the user to define a getType method on Sender interface. With
(1), this will result in something like:
public interface MySender {
@EventClass(DeleteEvent.class)
public Type<DeleteHandler> getDeleteType();
@Eventclass(DeleteEvent.class)
public void fireDelete(HasHandlers source...);
@EventClass(CreateEvent.class)
public Type<CreateHandler> getCreateType();
@Eventclass(CreateEvent.class)
public void fireCreate(HasHandlers source...);
...
}
Using such way, we can keep the GWT optimization of really firing an event only
if getType was called.
Note that the generators are not safe (no error check...) and I also used it to
find a way to rework the proxy generator.
Original comment by olivier....@free.fr
on 18 Aug 2010 at 9:35
Original comment by philippe.beaudoin
on 22 Sep 2010 at 1:35
Original comment by philippe.beaudoin
on 16 Jun 2011 at 1:21
Original issue reported on code.google.com by
philippe.beaudoin
on 28 Apr 2010 at 5:31