74 lines
3.1 KiB
Java
74 lines
3.1 KiB
Java
package tc.oc.commons.bukkit.event;
|
|
|
|
import java.lang.annotation.Annotation;
|
|
import java.lang.reflect.Method;
|
|
import java.lang.reflect.Modifier;
|
|
import java.util.stream.Stream;
|
|
import javax.annotation.Nullable;
|
|
|
|
import com.google.common.collect.SetMultimap;
|
|
import com.google.common.reflect.TypeToken;
|
|
import tc.oc.commons.core.exception.InvalidMemberException;
|
|
import tc.oc.commons.core.stream.Collectors;
|
|
import tc.oc.minecraft.api.event.Listener;
|
|
|
|
/**
|
|
* Scans classes for event handler methods that are denoted with a given annotation type.
|
|
*/
|
|
public abstract class EventHandlerScanner<Event, HandlerAnnotation extends Annotation, Info extends EventSubscriber<? extends Event>> {
|
|
|
|
protected final Class<Listener> listenerType;
|
|
protected final Class<Event> eventType;
|
|
protected final Class<HandlerAnnotation> annotationType;
|
|
|
|
public EventHandlerScanner() {
|
|
listenerType = (Class<Listener>) new TypeToken<Listener>(getClass()){}.getRawType();
|
|
eventType = (Class<Event>) new TypeToken<Event>(getClass()){}.getRawType();
|
|
annotationType = (Class<HandlerAnnotation>) new TypeToken<HandlerAnnotation>(getClass()){}.getRawType();
|
|
}
|
|
|
|
protected abstract Info createHandlerInfo(Method method,
|
|
Class<? extends Event> eventType,
|
|
HandlerAnnotation annotation);
|
|
|
|
public boolean isHandler(Method method) {
|
|
return findAnnotation(method) != null &&
|
|
!method.isBridge() &&
|
|
!method.isSynthetic();
|
|
}
|
|
|
|
public @Nullable HandlerAnnotation findAnnotation(Method method) {
|
|
return method.getAnnotation(annotationType);
|
|
}
|
|
|
|
public Class<? extends Event> findEventType(Method method) {
|
|
if(Modifier.isStatic(method.getModifiers())) {
|
|
throw new InvalidMemberException(method, "Event handler method cannot be static");
|
|
}
|
|
|
|
final Class<?>[] params = method.getParameterTypes();
|
|
final Class<?> type = params[0];
|
|
if(params.length != 1 || !eventType.isAssignableFrom(type)) {
|
|
throw new InvalidMemberException(method, "Event handler method must take a " + eventType.getName() + " as its first parameter");
|
|
}
|
|
return type.asSubclass(eventType);
|
|
}
|
|
|
|
public Stream<Method> findEventHandlerMethods(Class<? extends Listener> listener) {
|
|
return Stream.concat(
|
|
Stream.of(listener.getDeclaredMethods())
|
|
.filter(this::isHandler),
|
|
Stream.concat(Stream.of(listener.getSuperclass()),
|
|
Stream.of(listener.getInterfaces()))
|
|
.filter(ancestor -> ancestor != null && Listener.class.isAssignableFrom(ancestor))
|
|
.flatMap(ancestor -> findEventHandlerMethods((Class<? extends Listener>) ancestor))
|
|
);
|
|
}
|
|
|
|
public SetMultimap<EventKey<? extends Event>, Info> findEventHandlers(Class<? extends Listener> listener) {
|
|
return findEventHandlerMethods(listener)
|
|
.map(method -> createHandlerInfo(method, findEventType(method), findAnnotation(method)))
|
|
.collect(Collectors.toImmutableSetMultimap(EventSubscriber::key));
|
|
}
|
|
}
|