package org.unbrokendome.eventbus.proxy; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.unbrokendome.eventbus.Subscribe; import org.unbrokendome.eventbus.util.MethodSignature; import org.unbrokendome.eventbus.util.Reflection; import java.lang.reflect.Method; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; final class ReflectiveSubscriberScanner implements SubscriberScanner { private final Logger logger = LoggerFactory.getLogger(ReflectiveSubscriberScanner.class); @Override public Stream<EventSubscriberInfo> scanForSubscriberMethods(String beanName, Class<?> beanType) { return Reflection.allMethods(beanType) .filter(m -> m.isAnnotationPresent(Subscribe.class)) .filter(this::hasExactlyOneParameter) .filter(this::hasVoidReturnType) .collect(Collectors.groupingBy(MethodSignature::of)) .entrySet().stream() .map(e -> makeSubscriberInfo(beanName, beanType, e.getKey(), e.getValue())); } private EventSubscriberInfo makeSubscriberInfo(String beanName, Class<?> beanType, MethodSignature signature, List<Method> annotatedMethods) { Method methodToCall = Reflection.allMethodsMatching(beanType, signature) .min(Reflection.methodOverridesComparator()) .get(); Subscribe annotationToUse = Collections.max(annotatedMethods, Reflection.methodOverridesComparator()) .getAnnotation(Subscribe.class); return new ReflectiveEventSubscriberInfo(beanName, methodToCall.getDeclaringClass(), methodToCall, annotationToUse); } private boolean hasExactlyOneParameter(Method method) { if (method.getParameterCount() != 1) { logger.error("Method \"{}\" is annotated with @Subscribe but does not qualify as a subscriber " + "because it has {} parameters (must have exactly 1)", method, method.getParameterCount()); return false; } return true; } private boolean hasVoidReturnType(Method method) { if (method.getReturnType() != Void.TYPE) { logger.error("Method \"{}\" is annotated with @Subscribe but does not qualify as a subscriber " + "because it has a non-void return type", method); return false; } return true; } }