Creating generic GWT Events: is this a good approach? - java

I'm trying to create a simple way to fire CRUD-type events for different domain classes. I've created the following event class:
public class EntityModifiedEvent<E> extends Event<EntityModifiedEventHandler<E>> {
private E element;
private ModType modType;
private Class<E> clazz;
private static Map<String,GwtEvent.Type<EntityModifiedEventHandler<?>>> types = new HashMap<String, GwtEvent.Type<EntityModifiedEventHandler<?>>>();
public EntityModifiedEvent(ModType modType, E element, Class<E> clazz) {
this.element = element;
this.modType = modType;
this.clazz = clazz;
}
public Type<EntityModifiedEventHandler<?>> getType() {
return getType(clazz);
}
#SuppressWarnings({"rawtypes", "unchecked"})
public static GwtEvent.Type<EntityModifiedEventHandler<?>> getType(Class clazz) {
GwtEvent.Type type = types.get(clazz.toString());
if (type == null) {
type = new GwtEvent.Type<EntityModifiedEventHandler<?>>();
types.put(clazz.toString(), type);
}
return type;
}
public E getElement(){
return element;
}
public ModType getModType() {
return modType;
}
#SuppressWarnings({"unchecked", "rawtypes"})
#Override
public Type<EntityModifiedEventHandler<E>> getAssociatedType() {
return (Type) getType();
}
#Override
protected void dispatch(EntityModifiedEventHandler<E> handler) {
handler.onEntityModified(this);
};
public interface EntityModifiedEventHandler<E> extends EventHandler {
void onEntityModified(EntityModifiedEvent<E> entityModifiedEvent);
}
So, any class can register itself as a listener as follow:
getEventBus().addHandler(EntityModifiedEvent.getType(MyDomainClass.class), this);
And the events will be fired like:
getEventBus().fireEventFromSource(new EntityModifiedEvent<MyDomainClass>(ModType.CREATE, instanceModified, MyDomainClass.class), this);
ModType is just a simple Enum with the different types of modifications.
I have some concerns about having a map with all class.toString->eventTypes in this class itself. Do you think this will bring performance issues?
Also, this approach relies on the EventBus using Type object's hashcode to identify the handlers registered for that type (see getType(Class clazz) function). Do you think it's wrong to rely on it?
Any other suggestion about how to do this? Any comment will be much appreciated!

You have to ask yourself what do you gain from such an approach?
Performance - no. I don't have solid numbers on this (I'd have to be able to profile your application), but it's seems that this offers no measurable performance gains, if any. The number of fired events will be the same, but the number of receivers will be greater than with a more fine-grained approach. Plus, there's the type checking.
The ability to perform some common code when any entity modified event is fired, regardless of its type. This is true, but read on on how to achieve it with specific events.
Using specific events for the exact operation that was performed seems like a better choice:
It makes it clear who listens to what event.
The events can have extra metadata specific to the event (how many records where deleted, do you need to flush the cache, etc.)
I'd recommend looking at gwteventbinder to trim some of the boilerplate and improve your code. It also allows for handling several events in one method:
class SuperEvent extends GenericEvent { }
class EventOne extends SuperEvent { }
class EventTwo extends SuperEvent { }
class FormPresenter {
interface MyEventBinder extends EventBinder<FormPresenter> {}
private final MyEventBinder eventBinder = GWT.create(MyEventBinder.class);
FormPresenter(EventBus eventBus) {
eventBinder.bindEventHandlers(this, eventBus);
}
#EventHandler
void onEventOne(EventOne event) {
// handler for EventOne
}
#EventHandler(handles = {EventOne.class, EventTwo.class})
void onEventOneAndTwo(SuperEvent event) {
// handler for EventOne and EventTwo
}
#EventHandler(handles = {EventOne.class, EventTwo.class})
void onEventOneAndTwo2() {
// handler for EventOne and EventTwo without parameter
}
}

Related

Default/Mixin Generic In java

I am wondering if i can replace the generic type upon class initialization ( without inheritance ).
The case is as below .
I have bunch of generic actor + builder class in my module and distribute this to people who wants to use it in my team while keeping the actor and the entry point of fluent interface generic.
The requirement is how can people supply their own builder ( not extending ) to do the stuff they want.
Current state:
class MessageBuilder {
public MessageBuilder msg(String msg) {
//do something
}
}
class Actor {
public MessageBuilder newMessage() {
return new MessageBuilder();
}
}
class Main {
#Test
public void testActor() {
Actor actor = new Actor();
actor.newMessage().msg("sss").send();
}
}
Desired state:
class MessageBuilder{
public MessageBuilder msg(String msg) {
//do something
}
//more fluent api...
}
// project specific - dont want to extend from generic one as this should be contains its own fluent interface
class MyCustomMessageBuilder {
public MyCustomMessageBuilder rawstr(String rawstr) {
//do something
}
}
class Actor<T> {
public T newMessage() {
return (T)builderFactory.getInstance();
}
}
class Main {
#Test
public void testActor() {
Actor<MyCustomMessageBuilder> actor = new Actor(BuilderFactory);
actor.newMessage().rawstr("sss").send();
}
}
It's not possible without some known tricks.
First, Java implements Generics with type erasure (more information on type erasure), therefore the compiler will:
Replace all type parameters in generic types with their bounds or Object if the type parameters are unbounded. The produced bytecode, therefore, contains only ordinary classes, interfaces, and methods.
In practice, this means that Actor<Builder1> and Actor<Builder2> are the exact same class after it gets compiled. In both cases, newMessage is implemented as follows:
class Actor {
public Object newMessage() {
...
}
}
It's not possible for newMessage to have different implementations based on the type parameter and it's not possible for newMessage to ask for the type of T because it gets removed.
Having said that, you can pass in type information:
class Actor<T> {
private Class<T> klass;
public Actor(Class<T> klass) {
this.klass = klass;
}
public T newMessage() {
return klass.newInstance();
}
}
class Main {
#Test
public void testActor() {
Actor<MyCustomMessageBuilder> actor = new Actor<>(MyCustomMessageBuilder.class);
actor.newMessage().rawstr("sss").send();
}
}
I'd go with a factory approach. The builder should be supplied by a factory:
class Actor<MsgBuilder> {
private final Supplier<MsgBuilder> messageBuilderFactory;
public Actor(Supplier<MsgBuilder> builderFactory) {
this.messageBuilderFactory = builderFactory;
}
public MsgBuilder newMessage() {
return messageBuilderFactory.get();
}
}
This way offers flexibility in creating the message builder without sacrificing type safety and also no need for ugly casting.

Java: How to avoid "method not applicable for the arguments" error

I realize this type of question has been asked countless times, but I haven't found an answer that seems to address and/or explain what 1) I'm doing wrong and 2) what I need to do to get it right.
I have an application where I'm trying to manage a collection of queues. The users of the queue manager will ask for a queue by providing a unique ID and the manager will return the queue if it's already being managed, or create a new queue (via reflection) and return it if it has not yet been created.
I've coded the queue manager to use Java generics and am running into an issue that I don't understand, nor how to correct the problem.
Here is the queue manager:
public class QueueManager<T extends MessageType, C extends BlockingQueue<T>> {
private Map<UUID, C> queueMap;
public void removeQueue(UUID id) {
queueMap.remove(id);
}
public C getQueue(Class<C> clazz, UUID id) {
if (!queueMap.containsKey(id)) {
queueMap.put(id, constructQueue(clazz));
}
return queueMap.get(id);
}
private C constructQueue(Class<C> clazz) {
C result = null;
try {
Constructor<C> constructor = clazz.getDeclaredConstructor();
result = constructor.newInstance();
} catch (NoSuchMethodException | SecurityException | InstantiationException
| IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
// handle exception
}
return result;
}
}
Code that uses the queue manager:
public class QueueingListener<T extends MessageType> implements MessageListener<T> {
private QueueManager<T, BlockingQueue<T>> queueMgr = new QueueManager<>();
...
#Override
public void handleMessage(T message) {
...
queueMgr.getQueue(LinkedBlockingQueue.class,
message.getMessageHeader().getUUID());
...
}
The code complains with a compilation error:
The method getQueue(Class<BlockingQueue<T>>, UUID) in the type QueueManager<T,BlockingQueue<T>> is not applicable for the arguments (Class<LinkedBlockingQueue>, UUID)
Could someone please explain what is wrong here and what I need to do instead?
I'd really like to know where to find a really good tutorial on Java generics. I've looked at many sources, but they seem to cover only the basics to get someone going and don't cover more advanced concepts and finer details.
Why care about the type of queues that are managed, and why not just pass a Supplier<BlockingQueue> to the getter?
public class QueueManager<T extends MessageType> {
private Map<UUID, BlockingQueue<T>> queueMap;
public void removeQueue(UUID id) {
queueMap.remove(id);
}
public BlockingQueue<T> getQueue(UUID id, Supplier<BlockingQueue<T>> createQueue) {
return queueMap.computeIfAbsent(id, k -> createQueue.get());
}
// let's add a default while we're at it
public BlockingQueue<T> getQueue(UUID id) {
return getQueue(id, () -> new ArrayBlockingQueue<T>(50));
}
}
That would make the call
queueMgr.getQueue(message.getMessageHeader().getUUID(), LinkedBlockingQueue::new);
I'll summate the important parts of this code for the point I'm going to make:
public class QueueManager<T extends MessageType, C extends BlockingQueue<T>> {
public C getQueue(Class<C> clazz, UUID id) {
if (!queueMap.containsKey(id)) {
queueMap.put(id, constructQueue(clazz));
}
return queueMap.get(id);
}
}
Note here that C could be any class extending BlockingQueue when initially creating an instance of this class. However, once you create this object, C is set as some type of specific class. You later call the following code:
private QueueManager<T, BlockingQueue<T>> queueMgr = new QueueManager<>();
The line above defines C as a 'BlockingQueue'.
queueMgr.getQueue(LinkedBlockingQueue.class, message.getMessageHeader().getUUID());
However, in this line, you pass in a completely different object. LinkedBlockingQueue implements BlockingQueue, yes, but the Class objects for both respectively are completely different, and they are not specified by your class description. What you're looking for is a class of something that extends C in your method signature. Thus, the remedy to this error would be to modify your getQueue() method as such:
public <X extends C> C getQueue(Class<X> clazz, UUID id) {
if (!queueMap.containsKey(id)) {
queueMap.put(id, constructQueue(clazz));
}
return queueMap.get(id);
}
There is a subtle, but important, syntactic difference here that I hope I've explained clearly. You would also modify constructQueue() in a similar way. :)

FEST: Getting a component by his class (inherited from a basic component)

I have this code:
//FrameFixture frame = (...got it from window, main frame...)
JTableFixture table = frame.table(new GenericTypeMatcher<JTable>(JTable.class) {
#Override protected boolean isMatching(JTable table) {
return (table instanceof myTreeTable);
}
});
Isnt there any better kind of syntactic sugar for fetching a component by his .class (inheriting from a basic component)?
If you need implementation of ComponentMatcher then TypeMatcher can do matching based on type.
However TypeMatcher cannot be used in case of ContainerFixture.table methods as they require GenericTypeMatcher.
TypeMatcher and GenericTypeMatcher both implement ComponentMatcher but aren't in the same hierarchy.
GenericTypeMatcher is abstract, so you have to provide an implementation. You could get away with your own extension if needed, ie:
class ConcreteTypeMatcher<T extends Component> extends GenericTypeMatcher<T> {
Class<T> type;
public ConcreteTypeMatcher(Class<T> supportedType) {
super(supportedType);
this.type = supportedType;
}
#Override
protected boolean isMatching(T arg) {
return type.isInstance(arg);
}
}
And use it like this:
JTableFixture table = frame.table(
new ConcreteTypeMatcher<myTreeTable>(myTreeTable.class));

Downcasting and polymorphism without using instanceof? (Java)

Here's the sort of thing I'm trying to do:
class Foo {
private ArrayList<Widget> things; //Contains WidgetA, WidgetB and WidgetAB objects
//...
void process(int wIndex) {
process(things.get(wIndex);
}
private void process(WidgetA w) {
//Do things
}
private void process(WidgetB w) {
//Do other things
}
private void process(WidgetAB w) {
//Do completely different things
}
}
abstract class Widget {
//...
}
class WidgetA extends Widget {
//...
}
class WidgetB extends Widget {
}
class WidgetAB extends WidgetA {
}
Basically, a separate class gets an array index from user input, and passes it to the process(int) method, which is supposed to kick off a type-specific process() method to process the object at the passed index. The problem is that the objects are treated as Widget objects, not WidgetA, etc. I could loop through the types using instanceof, I guess, but I'm trying to avoid using that.
The logic in the process() methods needs to access private fields in the Foo class, so moving them to the Widget subclasses might not be the best idea.
So the question is, is there a way for the correct process() method to be called for a given Widget subtype, without using instanceof?
Yes, have a look at the Visitor pattern - also known as double dispatch.
Another potential solution is to use Java's reflection API's. Example:
class Foo {
private ArrayList<Widget> things; //Contains WidgetA, WidgetB and WidgetAB objects
//...
void process(int wIndex) {
Widget theWidget = things.get(wIndex);
try {
Class type = theWidget.getClass();
Class[] arg_types = new Class[]{type};
this.getMethod("process", arg_types).invoke(this, theWidget);
} catch (Exception e) {
//Could be SecurityException or NoSuchMethodException
}
}
private void process(WidgetA w) {
//Do things
}
private void process(WidgetB w) {
//Do other things
}
private void process(WidgetAB w) {
//Do completely different things
}
}
abstract class Widget {
//...
}
class WidgetA extends Widget {
//...
}
class WidgetB extends Widget {
}
class WidgetAB extends WidgetA {
}
The issue here being that you have to have defined a process() method for each type of object in the things list or an exception will be thrown at run-time. The compiler will not warn you if you are missing an implementation.

Events handling with generic handlers in java

I have written custom dispathing/handling event system that generally look like this:
Event handler interface:
public interface EventHandler{
}
Base event class:
public abstract class Event<H extends EventHandler> {
public static Class Type<H> { }
public abstract void dispatch(H handler);
}
Handler manager:
public class HandlerManager {
private Map<Event.Type, List<EventHandler>> map = new HashMap<Event.Type, List<EventHandler>>();
public void register(Event.Type<H> type, H handler) {
if(map.get(type) == null) { map.put(type, new ArrayList<EventHandler>()); }
map.get(type).add(handler);
}
public void fire(Event<H> event) {...}
...
}
And everything is working fine but i want to use events like
public class DataChangeEvent<D> extends Event<DataChangeHandler<D>> {
public static final Type<?> TYPE = new Type<?>();
D data;
...
public void dispatch(DataChangeHandler<D> handler) {
handler.onDataChanged(this);
}
public D getData() { return data; }
}
public class DataChangeHandler<D> extends EventHandler {
void onDataChanged(DataChangeEvent<D> event);
}
and now when I register handler DataChangeHandler with manager that generates events for Strings and for example for Integers, this registered handler will receive both events what causes ClassCastException to occure when I want to read data.
I understand that generic dont have some special class and that despite of type defined in DataChangeHandler they are stored in the same list in handlers map.
Is there any way to make it work?
This seems like a really, really smelly design. Why should an event be typed with the class that handles that type of event? That's backwards. An EventHandler should be typed with the type of Events it handles.
So I didn't quite follow what you're actually trying to do but I think you're basically trying to do this:
private Map<Class<?>, List<EventHandler>> map;
public <T> void register(Class<? extends T> typeFilter, EventHandler<T> handler) {
map.get(typeFilter).add(handler);
}
//...later
//safe since we used a generic method to add
#SuppressWarnings("unchecked");
public void fire(Event<?> event) {
for ( EventHandler handler : map.get(event.getClass()) ) {
handler.onDataChanged(event);
}
}
//or similarly:
#SuppressWarnings("unchecked");
public void fire(Event<?> event) {
for ( Class<?> type : map.keySet() ) {
if ( !type.instanceOf(event) ) continue;
for ( EventHandler handler : map.get(type) ) {
handler.onDataChanged(event);
}
}
}
This type of design will filter out events that the handler can't handle.
Generics are largely a compile time feature. If you need the type at runtime you need to pass the class as an arguement and store it in a field.
IMHO: A more elegent way of creating a dispacter is to use an annotation. Like
#EventHandler
public void onMyEvent(MyEvent event) {
// is called when MyEvent is dispacted.
}

Categories

Resources