ProjectAres/Util/bukkit/src/main/java/tc/oc/commons/bukkit/event/EventHandlerScanner.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));
}
}