Reputation: 3395
Our Java application uses Google Guava EventBus in the backend for communication. Some of those events are sent to client-side using Jersey's server-sent events support to enable notifications. Client-side is only interested in certain kinds of events and those events are sent to client-side in JSON format.
Currently we're using if-else
with instanceof
to handle the JSON body generation in a giant method. UIEvent
is only a marker interface which used as a filter.
@Subscribe
public void handleEvent(final UIEvent event) {
if (event instanceof A) {
A a = (A) event;
} else if (event instance B) {
B b = (B) event;
} ...
}
This code starts to get messy when more and more events are added to the system. After some research, there are some alternatives but not good enough.
1) Reflections.
Using reflections means we can use a declarative way to retrieve data from event objects without knowing the exact type. But using reflections is not type-safe and can be messy when dealing with nested path, e.g. a.b.c
.
2) Polymorphism
Polymorphism looks like a good alternative to instanceof
, but does really work in this case. Using polymorphism means adding method like toJSON
to UIEvent
interface. But this reverts the dependency flow and exposes UI details to event bus.
3) Wrapper classes
I'm also thinking about using event wrapper classes to encapsulate the JSON body building logic in separate classes. Then in the event bus's handleEvent
method, I can get the type of event object and find the wrapper class using naming convention, then construct wrapper class instances, invoke toJson
method to get the JSON body.
public class AWrapper {
public AWrapper(A a) {
}
public Object toJson() {
}
}
This is by far the most reasonable approach I can think of.
Need suggestions and ideas.
Upvotes: 5
Views: 1010
Reputation: 17045
I believeGoogle Guava EventBus was precisely designed so you didn't have to define such method with many if-else-if's:
Some have proposed a generic Handler interface for EventBus listeners. This runs into issues with Java's use of type erasure, not to mention problems in usability.
...
Due to erasure, no single class can implement a generic interface more than once with different type parameters. This is a giant step backwards from traditional Java Events, where even if actionPerformed and keyPressed aren't very meaningful names, at least you can implement both methods!
By creating your own marker, you are re-creating the problem they were trying to avoid.
EventBus eventBus = new EventBus();
eventBus.register(new Object(){
@Subscribe
public void handleEvent(A a) {
System.out.println("a");
}
});
eventBus.register(new Object(){
@Subscribe
public void handleEvent(B b) {
System.out.println("b");
}
});
...
eventBus.post(new A());
eventBus.post(new B());
One handler method per event type. Obviously, the subscribers don't need to be in anonymous classes like in this example.
http://tomaszdziurko.pl/2012/01/google-guava-eventbus-easy-elegant-publisher-subscriber-cases/
Upvotes: 1