Skip to content

Commit

Permalink
Improve handling of method discovery in AnnotatedEventManager (#2454)
Browse files Browse the repository at this point in the history
  • Loading branch information
freya022 authored Jun 3, 2023
1 parent 0c0b7b7 commit eada413
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 26 deletions.
2 changes: 1 addition & 1 deletion src/main/java/net/dv8tion/jda/api/JDABuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -1817,7 +1817,7 @@ public JDA build()
if (audioSendFactory != null)
jda.setAudioSendFactory(audioSendFactory);

listeners.forEach(jda::addEventListener);
jda.addEventListener(listeners.toArray());
jda.setStatus(JDA.Status.INITIALIZED); //This is already set by JDA internally, but this is to make sure the listeners catch it.

// Set the presence information before connecting to have the correct information ready when sending IDENTIFY
Expand Down
67 changes: 43 additions & 24 deletions src/main/java/net/dv8tion/jda/api/hooks/AnnotatedEventManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
import net.dv8tion.jda.api.events.GenericEvent;
import net.dv8tion.jda.internal.JDAImpl;
import net.dv8tion.jda.internal.utils.ClassWalker;
import net.dv8tion.jda.internal.utils.JDALogger;
import org.slf4j.Logger;

import javax.annotation.Nonnull;
import java.lang.reflect.InvocationTargetException;
Expand Down Expand Up @@ -51,21 +53,36 @@
*/
public class AnnotatedEventManager implements IEventManager
{
private static final Logger LOGGER = JDALogger.getLog(AnnotatedEventManager.class);
private final Set<Object> listeners = ConcurrentHashMap.newKeySet();
private final Map<Class<?>, Map<Object, List<Method>>> methods = new ConcurrentHashMap<>();

@Override
public void register(@Nonnull Object listener)
{
if (listener.getClass().isArray())
{
for (Object o : ((Object[]) listener))
register(o);
return;
}

if (listeners.add(listener))
{
updateMethods();
registerListenerMethods(listener);
}
}

@Override
public void unregister(@Nonnull Object listener)
{
if (listener.getClass().isArray())
{
for (Object o : ((Object[]) listener))
unregister(o);
return;
}

if (listeners.remove(listener))
{
updateMethods();
Expand Down Expand Up @@ -114,32 +131,34 @@ private void updateMethods()
methods.clear();
for (Object listener : listeners)
{
boolean isClass = listener instanceof Class;
Class<?> c = isClass ? (Class) listener : listener.getClass();
Method[] allMethods = c.getDeclaredMethods();
for (Method m : allMethods)
{
if (!m.isAnnotationPresent(SubscribeEvent.class) || (isClass && !Modifier.isStatic(m.getModifiers())))
{
continue;
}
Class<?>[] pType = m.getParameterTypes();
if (pType.length == 1 && GenericEvent.class.isAssignableFrom(pType[0]))
{
Class<?> eventClass = pType[0];
if (!methods.containsKey(eventClass))
{
methods.put(eventClass, new ConcurrentHashMap<>());
}
registerListenerMethods(listener);
}
}

if (!methods.get(eventClass).containsKey(listener))
{
methods.get(eventClass).put(listener, new CopyOnWriteArrayList<>());
}
private void registerListenerMethods(Object listener)
{
boolean isClass = listener instanceof Class;
Class<?> c = isClass ? (Class<?>) listener : listener.getClass();
Method[] allMethods = c.getDeclaredMethods();
for (Method m : allMethods)
{
if (!m.isAnnotationPresent(SubscribeEvent.class))
continue;
//Skip member methods if listener is a Class
if (isClass && !Modifier.isStatic(m.getModifiers()))
continue;

methods.get(eventClass).get(listener).add(m);
}
final Class<?>[] parameterTypes = m.getParameterTypes();
if (parameterTypes.length != 1 || !GenericEvent.class.isAssignableFrom(parameterTypes[0]))
{
LOGGER.warn("Method '{}' annotated with @{} must have at most 1 parameter, which implements GenericEvent", m, SubscribeEvent.class.getSimpleName());
continue;
}

Class<?> eventClass = parameterTypes[0];
methods.computeIfAbsent(eventClass, k -> new ConcurrentHashMap<>())
.computeIfAbsent(listener, k -> new CopyOnWriteArrayList<>())
.add(m);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,7 @@ protected JDAImpl buildInstance(final int shardId)
if (this.sessionConfig.getAudioSendFactory() != null)
jda.setAudioSendFactory(this.sessionConfig.getAudioSendFactory());

this.eventConfig.getListeners().forEach(jda::addEventListener);
jda.addEventListener(this.eventConfig.getListeners().toArray());
this.eventConfig.getListenerProviders().forEach(provider -> jda.addEventListener(provider.apply(shardId)));

// Set the presence information before connecting to have the correct information ready when sending IDENTIFY
Expand Down

0 comments on commit eada413

Please sign in to comment.