src/main/java/io/github/classgraph/ClassInfo.java
private ReachableAndDirectlyRelatedClasses filterClassInfo(final RelType relType, final boolean strictWhitelist,
            final ClassType... classTypes) {
        Set<ClassInfo> directlyRelatedClasses = this.relatedClasses.get(relType);
        if (directlyRelatedClasses == null) {
            return NO_REACHABLE_CLASSES;
        } else {
            // Clone collection to prevent users modifying contents accidentally or intentionally
            directlyRelatedClasses = new LinkedHashSet<>(directlyRelatedClasses);
        }
        final Set<ClassInfo> reachableClasses = new LinkedHashSet<>(directlyRelatedClasses);
        if (relType == RelType.METHOD_ANNOTATIONS || relType == RelType.METHOD_PARAMETER_ANNOTATIONS
                || relType == RelType.FIELD_ANNOTATIONS) {
            // For method and field annotations, need to change the RelType when finding meta-annotations
            for (final ClassInfo annotation : directlyRelatedClasses) {
                reachableClasses.addAll(
                        annotation.filterClassInfo(RelType.CLASS_ANNOTATIONS, strictWhitelist).reachableClasses);
            }
        } else if (relType == RelType.CLASSES_WITH_METHOD_ANNOTATION
                || relType == RelType.CLASSES_WITH_METHOD_PARAMETER_ANNOTATION
                || relType == RelType.CLASSES_WITH_FIELD_ANNOTATION) {
            // If looking for meta-annotated methods or fields, need to find all meta-annotated annotations, then
            // look for the methods or fields that they annotate
            for (final ClassInfo subAnnotation : this.filterClassInfo(RelType.CLASSES_WITH_ANNOTATION,
                    strictWhitelist, ClassType.ANNOTATION).reachableClasses) {
                final Set<ClassInfo> annotatedClasses = subAnnotation.relatedClasses.get(relType);
                if (annotatedClasses != null) {
                    reachableClasses.addAll(annotatedClasses);
                }
            }
        } else {
            // For other relationship types, the reachable type stays the same over the transitive closure. Find the
            // transitive closure, breaking cycles where necessary.
            final LinkedList<ClassInfo> queue = new LinkedList<>(directlyRelatedClasses);
            while (!queue.isEmpty()) {
                final ClassInfo head = queue.removeFirst();
                final Set<ClassInfo> headRelatedClasses = head.relatedClasses.get(relType);
                if (headRelatedClasses != null) {
                    for (final ClassInfo directlyReachableFromHead : headRelatedClasses) {
                        // Don't get in cycle
                        if (reachableClasses.add(directlyReachableFromHead)) {
                            queue.add(directlyReachableFromHead);
                        }
                    }
                }
            }
        }
        if (reachableClasses.isEmpty()) {
            return NO_REACHABLE_CLASSES;
        }

        if (relType == RelType.CLASS_ANNOTATIONS || relType == RelType.METHOD_ANNOTATIONS
                || relType == RelType.METHOD_PARAMETER_ANNOTATIONS || relType == RelType.FIELD_ANNOTATIONS) {
            // Special case -- don't inherit java.lang.annotation.* meta-annotations as related meta-annotations
            // (but still return them as direct meta-annotations on annotation classes).
            Set<ClassInfo> reachableClassesToRemove = null;
            for (final ClassInfo reachableClassInfo : reachableClasses) {
                // Remove all java.lang.annotation annotations that are not directly related to this class
                if (reachableClassInfo.getName().startsWith("java.lang.annotation.")
                        && !directlyRelatedClasses.contains(reachableClassInfo)) {
                    if (reachableClassesToRemove == null) {
                        reachableClassesToRemove = new LinkedHashSet<>();
                    }
                    reachableClassesToRemove.add(reachableClassInfo);
                }
            }
            if (reachableClassesToRemove != null) {
                reachableClasses.removeAll(reachableClassesToRemove);
            }
        }

        return new ReachableAndDirectlyRelatedClasses(
                filterClassInfo(reachableClasses, scanResult.scanSpec, strictWhitelist, classTypes),
                filterClassInfo(directlyRelatedClasses, scanResult.scanSpec, strictWhitelist, classTypes));

    }
/**
     * Get the classes related to this one (the transitive closure) for the given relationship type, and those
     * directly related.
     *
     * @param relType
     *            the rel type
     * @param strictWhitelist
     *            the strict whitelist
     * @param classTypes
     *            the class types
     * @return the reachable and directly related classes
     */
Get the classes related to this one (the transitive closure) for the given relationship type, and those
directly related.

@param relType
the rel type
@param strictWhitelist
the strict whitelist
@param classTypes
the class types
@return the reachable and directly related classes
Get the classes related to this one ( the transitive closure ) for the given relationship type and those directly related . @param relType the rel type @param strictWhitelist the strict whitelist @param classTypes the class types @return the reachable and directly related classes
private ReachableAndDirectlyRelatedClasses filterClassInfo(final RelType relType, final boolean strictWhitelist,
            final ClassType... classTypes) {
        Set<ClassInfo> directlyRelatedClasses = this.relatedClasses.get(relType);
        if (directlyRelatedClasses == null) {
            return NO_REACHABLE_CLASSES;
        } else {
            directlyRelatedClasses = new LinkedHashSet<>(directlyRelatedClasses);
        }
        final Set<ClassInfo> reachableClasses = new LinkedHashSet<>(directlyRelatedClasses);
        if (relType == RelType.METHOD_ANNOTATIONS || relType == RelType.METHOD_PARAMETER_ANNOTATIONS
                || relType == RelType.FIELD_ANNOTATIONS) {
            for (final ClassInfo annotation : directlyRelatedClasses) {
                reachableClasses.addAll(
                        annotation.filterClassInfo(RelType.CLASS_ANNOTATIONS, strictWhitelist).reachableClasses);
            }
        } else if (relType == RelType.CLASSES_WITH_METHOD_ANNOTATION
                || relType == RelType.CLASSES_WITH_METHOD_PARAMETER_ANNOTATION
                || relType == RelType.CLASSES_WITH_FIELD_ANNOTATION) {
            for (final ClassInfo subAnnotation : this.filterClassInfo(RelType.CLASSES_WITH_ANNOTATION,
                    strictWhitelist, ClassType.ANNOTATION).reachableClasses) {
                final Set<ClassInfo> annotatedClasses = subAnnotation.relatedClasses.get(relType);
                if (annotatedClasses != null) {
                    reachableClasses.addAll(annotatedClasses);
                }
            }
        } else {
            final LinkedList<ClassInfo> queue = new LinkedList<>(directlyRelatedClasses);
            while (!queue.isEmpty()) {
                final ClassInfo head = queue.removeFirst();
                final Set<ClassInfo> headRelatedClasses = head.relatedClasses.get(relType);
                if (headRelatedClasses != null) {
                    for (final ClassInfo directlyReachableFromHead : headRelatedClasses) {
                        if (reachableClasses.add(directlyReachableFromHead)) {
                            queue.add(directlyReachableFromHead);
                        }
                    }
                }
            }
        }
        if (reachableClasses.isEmpty()) {
            return NO_REACHABLE_CLASSES;
        }
        if (relType == RelType.CLASS_ANNOTATIONS || relType == RelType.METHOD_ANNOTATIONS
                || relType == RelType.METHOD_PARAMETER_ANNOTATIONS || relType == RelType.FIELD_ANNOTATIONS) {
            Set<ClassInfo> reachableClassesToRemove = null;
            for (final ClassInfo reachableClassInfo : reachableClasses) {
                if (reachableClassInfo.getName().startsWith("java.lang.annotation.")
                        && !directlyRelatedClasses.contains(reachableClassInfo)) {
                    if (reachableClassesToRemove == null) {
                        reachableClassesToRemove = new LinkedHashSet<>();
                    }
                    reachableClassesToRemove.add(reachableClassInfo);
                }
            }
            if (reachableClassesToRemove != null) {
                reachableClasses.removeAll(reachableClassesToRemove);
            }
        }
        return new ReachableAndDirectlyRelatedClasses(
                filterClassInfo(reachableClasses, scanResult.scanSpec, strictWhitelist, classTypes),
                filterClassInfo(directlyRelatedClasses, scanResult.scanSpec, strictWhitelist, classTypes));
    }
private ReachableAndDirectlyRelatedClasses filterClassInfo ( final RelType relType , final boolean strictWhitelist , final ClassType ... classTypes ) { Set < ClassInfo > directlyRelatedClasses = this . relatedClasses . get ( relType ) ; if ( directlyRelatedClasses == null ) { return NO_REACHABLE_CLASSES ; } else { directlyRelatedClasses = new LinkedHashSet < > ( directlyRelatedClasses ) ; } final Set < ClassInfo > reachableClasses = new LinkedHashSet < > ( directlyRelatedClasses ) ; if ( relType == RelType . METHOD_ANNOTATIONS || relType == RelType . METHOD_PARAMETER_ANNOTATIONS || relType == RelType . FIELD_ANNOTATIONS ) { for ( final ClassInfo annotation : directlyRelatedClasses ) { reachableClasses . addAll ( annotation . filterClassInfo ( RelType . CLASS_ANNOTATIONS , strictWhitelist ) . reachableClasses ) ; } } else if ( relType == RelType . CLASSES_WITH_METHOD_ANNOTATION || relType == RelType . CLASSES_WITH_METHOD_PARAMETER_ANNOTATION || relType == RelType . CLASSES_WITH_FIELD_ANNOTATION ) { for ( final ClassInfo subAnnotation : this . filterClassInfo ( RelType . CLASSES_WITH_ANNOTATION , strictWhitelist , ClassType . ANNOTATION ) . reachableClasses ) { final Set < ClassInfo > annotatedClasses = subAnnotation . relatedClasses . get ( relType ) ; if ( annotatedClasses != null ) { reachableClasses . addAll ( annotatedClasses ) ; } } } else { final LinkedList < ClassInfo > queue = new LinkedList < > ( directlyRelatedClasses ) ; while ( ! queue . isEmpty ( ) ) { final ClassInfo head = queue . removeFirst ( ) ; final Set < ClassInfo > headRelatedClasses = head . relatedClasses . get ( relType ) ; if ( headRelatedClasses != null ) { for ( final ClassInfo directlyReachableFromHead : headRelatedClasses ) { if ( reachableClasses . add ( directlyReachableFromHead ) ) { queue . add ( directlyReachableFromHead ) ; } } } } } if ( reachableClasses . isEmpty ( ) ) { return NO_REACHABLE_CLASSES ; } if ( relType == RelType . CLASS_ANNOTATIONS || relType == RelType . METHOD_ANNOTATIONS || relType == RelType . METHOD_PARAMETER_ANNOTATIONS || relType == RelType . FIELD_ANNOTATIONS ) { Set < ClassInfo > reachableClassesToRemove = null ; for ( final ClassInfo reachableClassInfo : reachableClasses ) { if ( reachableClassInfo . getName ( ) . startsWith ( "java.lang.annotation." ) && ! directlyRelatedClasses . contains ( reachableClassInfo ) ) { if ( reachableClassesToRemove == null ) { reachableClassesToRemove = new LinkedHashSet < > ( ) ; } reachableClassesToRemove . add ( reachableClassInfo ) ; } } if ( reachableClassesToRemove != null ) { reachableClasses . removeAll ( reachableClassesToRemove ) ; } } return new ReachableAndDirectlyRelatedClasses ( filterClassInfo ( reachableClasses , scanResult . scanSpec , strictWhitelist , classTypes ) , filterClassInfo ( directlyRelatedClasses , scanResult . scanSpec , strictWhitelist , classTypes ) ) ; }
Get the classes related to this one (the transitive closure) for the given relationship type, and those
 directly related.
Get the classes related to this one ( the transitive closure ) for the given relationship type and those directly related .
// Clone collection to prevent users modifying contents accidentally or intentionally // For method and field annotations, need to change the RelType when finding meta-annotations // If looking for meta-annotated methods or fields, need to find all meta-annotated annotations, then // look for the methods or fields that they annotate // For other relationship types, the reachable type stays the same over the transitive closure. Find the // transitive closure, breaking cycles where necessary. // Don't get in cycle // Special case -- don't inherit java.lang.annotation.* meta-annotations as related meta-annotations // (but still return them as direct meta-annotations on annotation classes). // Remove all java.lang.annotation annotations that are not directly related to this class