Map with Generics

I got a class called EnchantmentStack<E extends Event>. And in that class there is a method called trigger(E event) And when you create a new EnchantmentStack, it gets stored in a map like this: Map<Event, List<EnchantmentStack<?>>> And when a certain event happens. I get all the events and loop in them calling the trigger method. But it won't work because it's not type safe and the generic is unknown <?>. So is there a way to solve it? Like I could call them and trigger them with the known event
39 Replies
dan1st
dan1st•4w ago
basically you'd have to cast it
<E extends Event> void triggerListeners(E event) {
List<EnchantmentStack<E>> listeners = (List<EnchantmentStack<E>>) listenerMap.get(event);
for(EnchantmentStack<E> stack : listeners) {
stack.trigger(event);
}
}
<E extends Event> void triggerListeners(E event) {
List<EnchantmentStack<E>> listeners = (List<EnchantmentStack<E>>) listenerMap.get(event);
for(EnchantmentStack<E> stack : listeners) {
stack.trigger(event);
}
}
or
<E extends Event> void triggerListeners(E event) {
List<EnchantmentStack<?>> listeners = listenerMap.get(event);
for(EnchantmentStack<?> stack : listeners) {
stack.trigger(event);
}
}
private <E> void doTrigger(EnchantmentStack<E> stack, Event event) {
stack.trigger((E)event);
}
<E extends Event> void triggerListeners(E event) {
List<EnchantmentStack<?>> listeners = listenerMap.get(event);
for(EnchantmentStack<?> stack : listeners) {
stack.trigger(event);
}
}
private <E> void doTrigger(EnchantmentStack<E> stack, Event event) {
stack.trigger((E)event);
}
but do you really want events as the keys and not event types?
MDT 168
MDT 168OP•4w ago
The problem is that the map is static, and the method that triggers all of them is static public static void triggerEnchants(Event event) { for (EnchantmentStack<?> stack : triggers.get(event)) { stack.trigger(event); // This doesn't work } } So you can't really use generics for it
dan1st
dan1st•4w ago
That's why I put casts in the code
MDT 168
MDT 168OP•4w ago
So casting is enough?
dan1st
dan1st•4w ago
if you do it like that, it would work but it isn't type safe
MDT 168
MDT 168OP•4w ago
I didn't use generics much before. But I wanted to make a chance in my system So it may make errors if the Generic type and the event doesn't match?
dan1st
dan1st•4w ago
you can't do it in a type-safe way just with a Map If the Map only contains entries where the key matches the value, no
MDT 168
MDT 168OP•4w ago
No description
MDT 168
MDT 168OP•4w ago
It's like this. BlockDropItemEvent
dan1st
dan1st•4w ago
If the register method ensures the event matches the listener, you wouldn't get the errors
MDT 168
MDT 168OP•4w ago
Okay good. But what is better. Do I store the event itselfEvent or do I store the Class<? extends Event>
dan1st
dan1st•4w ago
that's what I mentioned before - if you use the Event as the key, the listeners would be for that specific event only so if you have data associated with the event, it would need to be the exact same data If you use the Class as the key, it would be the type of event
MDT 168
MDT 168OP•4w ago
Ooooo. I think I should use the Class for the Key,
Madjosz
Madjosz•4w ago
We are using the same construction for event listeners in our codebase so this is a common pattern. Unfortunately the Java type system is not powerful enough to have such associated generics to have the call typesafe without casting.
MDT 168
MDT 168OP•4w ago
The Event got data yes. So it will always be null when I try to get from the map right? I should use the Class It will be safe if I disturbute the enchantment stacks and the events correctly
Madjosz
Madjosz•4w ago
It is safe when you are caring for the correct type while putting/adding.
MDT 168
MDT 168OP•4w ago
This is the method
MDT 168
MDT 168OP•4w ago
No description
MDT 168
MDT 168OP•4w ago
This is the method
MDT 168
MDT 168OP•4w ago
No description
MDT 168
MDT 168OP•4w ago
No description
MDT 168
MDT 168OP•4w ago
Should this method work?
MDT 168
MDT 168OP•4w ago
No description
MDT 168
MDT 168OP•4w ago
No description
dan1st
dan1st•4w ago
I think it is possible with a small trick but not practical i.e. you'd need a different Map implementation that allows you to get the entry (which needs to be of a custom class) for any given key
Madjosz
Madjosz•4w ago
You are thinking of reified generics?
dan1st
dan1st•4w ago
no
Madjosz
Madjosz•4w ago
This just sounds like hiding the unsafe cast behind another method.
MDT 168
MDT 168OP•4w ago
So I should just cast it? Should this one work? This is the old code
dan1st
dan1st•4w ago
yes
MDT 168
MDT 168OP•4w ago
But how? I am not too bright with generics Never used them before in situations like these
dan1st
dan1st•4w ago
not on its own
MDT 168
MDT 168OP•4w ago
Wdym?
dan1st
dan1st•4w ago
something like that
Map<Class<? extends Event>, List<? extends EnchantmentStack<?>>> listenerMap = new HashMap<>();

<E extends Event> void triggerListeners(E event) {
List<EnchantmentStack<E>> listeners = (List<EnchantmentStack<E>>) listenerMap.get(event.getClass()); // unsafe here
for(EnchantmentStack<E> stack : listeners) {
stack.trigger(event); // but only used here
}
}

private <E extends Event> void addStack(Class<E> type, EnchantmentStack<E> stack) {
listenerMap.put(type, stack);
}
Map<Class<? extends Event>, List<? extends EnchantmentStack<?>>> listenerMap = new HashMap<>();

<E extends Event> void triggerListeners(E event) {
List<EnchantmentStack<E>> listeners = (List<EnchantmentStack<E>>) listenerMap.get(event.getClass()); // unsafe here
for(EnchantmentStack<E> stack : listeners) {
stack.trigger(event); // but only used here
}
}

private <E extends Event> void addStack(Class<E> type, EnchantmentStack<E> stack) {
listenerMap.put(type, stack);
}
While that solution includes an unsafe cast, you can be sure that it shouldn't throw an exception due to it if you only insert stuff via addStack it doesn't include the logic that ensures that you only have the right event
MDT 168
MDT 168OP•4w ago
I will try this. Thanks It says that I cannot cast Inconvertible types
dan1st
dan1st•4w ago
where exactly?
MDT 168
MDT 168OP•4w ago
On the cast. List<...> listeners = (...) ...; The first line of the method Oh wait. You use EnchantmentStack The list is MysticEnchantmentComponent Ugh still inconvertible types
dan1st
dan1st•4w ago
oh, my fault I edited it
JavaBot
JavaBot•4w ago
💤 Post marked as dormant
This post has been inactive for over 300 minutes, thus, it has been archived. If your question was not answered yet, feel free to re-open this post or create a new one. In case your post is not getting any attention, you can try to use /help ping. Warning: abusing this will result in moderative actions taken against you.

Did you find this page helpful?