@ SuppressWarnings ( "unchecked" ) @ VisibleForTesting Map < String , Class < ? extends Service > > mapEventSources ( ) throws IOException { /* Obtains all classpath's top level classes */ ClassLoader classLoader = Thread . currentThread ( ) . getContextClassLoader ( ) ; Set < ClassPath . ClassInfo > classes = ClassPath . from ( classLoader ) . getAllClasses ( ) ; ClassLoaderRepository repository = new ClassLoaderRepository ( classLoader ) ; LOGGER . info ( "Scanning classpath for EventHandlers...." ) ; /* iterates over all classes, filter by HandlesEvent annotation and transforms stream to needed form */ Map < String , Class < ? extends Service > > collected = classes . parallelStream ( ) /* loads class infos */ . map ( classInfo -> { try { /* sometimes exception occurs during class loading. Return empty/absent in this case */ return Optional . of ( repository . loadClass ( classInfo . getName ( ) ) ) ; } catch ( ClassNotFoundException e ) { LOGGER . trace ( "Class cannot be loaded: {}" , classInfo . getName ( ) , e ) ; return Optional . < JavaClass > empty ( ) ; } } ) /* filters classes which is present and marked with EventSource annotation */ . filter ( ( ( Predicate < Optional < JavaClass > > ) Optional :: isPresent ) . and ( javaClassOptional -> { return Arrays . stream ( javaClassOptional . get ( ) . getAnnotationEntries ( ) ) . anyMatch ( annotationEntry -> { return Type . getType ( annotationEntry . getAnnotationType ( ) ) . toString ( ) . equals ( EventSource . class . getCanonicalName ( ) ) ; } ) ; } ) . and ( javaClassOptional -> { try { return Arrays . stream ( javaClassOptional . get ( ) . getAllInterfaces ( ) ) . anyMatch ( iface -> { return iface . getClassName ( ) . equals ( Service . class . getCanonicalName ( ) ) ; } ) ; } catch ( ClassNotFoundException e ) { LOGGER . trace ( "Class annotations cannot be loaded: {}" , javaClassOptional . get ( ) . getClassName ( ) , e ) ; return false ; } } ) ) /* transforms from Optional<JavaClass> to Class (obtaining values from Optionals) */ . map ( javaClassOptional -> { try { return ( Class < ? extends Service > ) classLoader . loadClass ( javaClassOptional . get ( ) . getClassName ( ) ) ; } catch ( ClassNotFoundException e ) { LOGGER . trace ( "Class cannot be loaded: {}" , javaClassOptional . get ( ) . getClassName ( ) , e ) ; return null ; } } ) . filter ( Objects :: nonNull ) . collect ( Collectors . toMap ( clazz -> clazz . getAnnotation ( EventSource . class ) . value ( ) , clazz -> clazz ) ) ; LOGGER . info ( "Found {} event handlers" , collected . size ( ) ) ; return collected ; }
Scans whole application classpath and finds events sources