In my Java event bus project, I have a private generic method that retrieves a Set<Subscriber<E>>
from a private Map<Class<? extends Event>, Set<Subscriber<? extends Event>>>
(the subscriberMap
).
/**
* A map of Event types and Subscriber Sets.
*
* That is, the Set of Subscribers set to an Event type
* is assumed to be used for that Event type.
*/
private final Map<Class<? extends Event>, Set<Subscriber<? extends Event>>> subscriberMap = new ConcurrentHashMap<>();
private <E extends Event> void checkSubscriberMap(Class<E> type)
{
if (!subscriberMap.containsKey(type))
{
subscriberMap.put(type, new HashSet<>());
}
}
/**
* Gets a Set of Subscribers by an Event.
*
* @param event the event
* @param <E> the type of event
* @return a Set of Subscribers
*/
@SuppressWarnings("unchecked")
private <E extends Event> Set<Subscriber<E>> getSubscribers(E event)
{
return (Set<Subscriber<E>>) (Object) getSubscribers(event.getClass());
}
/**
* Gets a Set of Subscribers by an Event type.
*
* @param type the event class
* @param <E> the type of event
* @return a Set of Subscribers
*/
@SuppressWarnings("unchecked")
private <E extends Event> Set<Subscriber<E>> getSubscribers(Class<E> type)
{
checkSubscriberMap(type); // checks if subscriberMap.get(type) is null
return (Set<Subscriber<E>>) (Object) subscriberMap.get(type);
}
Assuming nobody uses reflection to modify subscriberMap
, the public methods that modify subscriberMap
only work if the Subscriber<? extends Event>
is the same type as the Class<? extends Event>
. Therefore, I can be sure that getSubscribers()
will always return a Set
of the same type that you give it.
/**
* Registers a single event handler under an explicit Event type.
* Returns true if the handler was added.
*
* @param subscriber the Subscriber
* @param type the type of Event
*/
public <E extends Event> boolean register(Subscriber<E> subscriber, Class<E> type)
{
if(type == Event.class)
{
throw new IllegalArgumentException("The provided type is not a subclass of Event.");
}
return getSubscribers(type).add(subscriber);
}
However, it's bothering me how getSubscribers()
looks. Why does it look I'm doing a hacky workaround? Is it necessary that I have to cast subscriberMap.get(type)
twice? Is this the right way to go about what I'm trying to do?