SuperEventBus is a high-powered event bus for GWT. It is a replacement for the built-in com.google.web.bindery.event.shared.EventBus.
SuperEventBus is currently an experimental API that is subject to change. Please leave feedback and feature requests in the issue tracker!
GWT's event bus is a great way to make your application more maintainable by decoupling components from one another, allowing you to work on one without affecting the others. However, the built-in event bus has several limitations. Specifically,
Event
class, requiring you to define a new event for any kind of data that must be
posted on the event bus. Like Guava's event bus, SuperEventBus allows you to
post any type of event, allowing you to do things like update model objects
by posting them directly on the bus. Handlers in GWT's event bus are also
always active when registered - SuperEventBus allows you to define filters
that can prevent events from being handled in certain situations (say, when
the component is not visible.)Event
requires implementing several boilerplate
methods, and registering handlers usually requires creating clunky anonymous
classes. SuperEventBus again takes inspiration from Guava, allowing you to
annotate existing methods with the @Subscribe
annotation to cause them to
be automatically registered as event handlers.Object
that will receive every event in the
system. When just a single polymorphic type still isn't enough, SuperEventBus
also allows the use of MultiEvents to handle many events with unrelated types
using a single handler method.SuperEventBus addresses all of these problems and more, providing a more powerful event bus that is easier to use.
SuperEventBus uses a simple annotation-based interface inspired by Guava's event
bus. To define a handler method, just annotate a non-private method that
takes a single argument with the @Subscribe
annotation like this:
@Subscribe
void handleString(String event) {
Window.alert("The string " + event + " was posted on the event bus.");
}
A class may contain any number of methods annotated with @Subscribe
. In order
to active them, the class must first declare an event registration interface for
the class:
interface MyRegistration extends EventRegistration<MyClass> {}
Then, the class just needs to register itself with an instance of the event bus (this is usually done in the constructor of the class):
@Inject
public MyClass(MyRegistration registration) {
eventBus.register(this, registration);
}
Note that if you're not using Gin, you can also create MyRegistration directly
via GWT.create instead of injecting it. Once registered, handleString
will
be invoked whenever a String
is posted on the event bus, which is done like
this:
eventBus.post("some string");
Of course, you aren't restricted to posting strings: handler methods can be
defined for any type and any type can be passed to post
. In practice, most
users will define their own event types rather than posting existing types
directly.
SuperEventBus contains several advanced features that have no analogue in GWT's built-in event bus. It's easy to get started with SuperEventBus without these features, and explore them later as needed.
In addition to @Subscribe
, handler methods can also be annotated with the
@WithPriority
annotation, which takes a single integer. Handlers with higher
priorities are always invoked before handlers with lower priorities. Handlers
without the @WithPriority
annotation are given priority 0, and negative
priorities are allowed. See the javadoc for more details.
Handler methods can also be annotated with the @When
annotation, which takes
a filter class and causes that handler to be ignored when the filter returns
false. Filter classes extend EventFilter
and look like this:
class IsVisible implements EventFilter<HasVisibility, Object> {
@Override
public boolean accepts(HasVisibility handler, Object event) {
return handler.isVisible();
}
}
A handler annotated with @When(IsVisible.class)
would be invoked only if its
containing class was visible at the time the event was posted. Note that the
filter accepts both the handler class as well as the event, so it is possible
to filter based on the properties of either. See the javadoc for more
details.
Since EventBus is polymorphic, it is usually possible to handle many types of
events by defining a handler for a common base class of those events. However,
sometimes it is necessary to handle multiple events of unrelated types. This
can be accomplished by declaring a handler with a paramter of type MultiEvent
and annotating it with EventTypes
as follows:
@Subscribe
void handleMultipleTypes(@EventTypes({String.class, Double.class}) MultiEvent event) {
if (event instanceof String) {
Window.alert("Got a string: " + event.getEvent());
} else if (event instanceof Double) {
Window.alert("Got a double: " + event.getEvent());
}
}
The given handler would be invoked whenever a String
or Double
was posted on
the event bus, and the actual event would be accessible via the getEvent
method
on MultiEvent
. See the javadoc for more details.
If an event is fired that has no registered handlers, SuperEventBus will wrap
that event in a DeadEvent
and re-fire it. This makes it possible to register a
handler for DeadEvent
that can do something like log a warning when an event
without a handler is fired, which can help detect misconfiguration issues. Note
that DeadEvent
will never be fired if a handler for Object
is registered,
since that handler will receive every event posted on the event bus. See the
javadoc for more details.
If you're using Maven, you can add the following to your <dependencies>
section:
<dependency>
<groupId>com.ekuefler.supereventbus</groupId>
<artifactId>supereventbus</artifactId>
<version>0.1.1</version>
</dependency>
You can also download the jar directly or check out the source using git from https://github.com/ekuefler/gwt-supereventbus.git.