/**
  * expand super types after scanning, for super types that were not scanned. this is helpful in
  * finding the transitive closure without scanning all 3rd party dependencies. it uses {@link
  * ReflectionUtils#getSuperTypes(Class)}.
  *
  * <p>for example, for classes A,B,C where A supertype of B, B supertype of C:
  *
  * <ul>
  *   <li>if scanning C resulted in B (B->C in store), but A was not scanned (although A supertype
  *       of B) - then getSubTypes(A) will not return C
  *   <li>if expanding supertypes, B will be expanded with A (A->B in store) - then getSubTypes(A)
  *       will return C
  * </ul>
  */
 public void expandSuperTypes() {
   if (store.keySet().contains(index(SubTypesScanner.class))) {
     Multimap<String, String> mmap = store.get(index(SubTypesScanner.class));
     Sets.SetView<String> keys = Sets.difference(mmap.keySet(), Sets.newHashSet(mmap.values()));
     Multimap<String, String> expand = HashMultimap.create();
     for (String key : keys) {
       expandSupertypes(expand, key, forName(key));
     }
     mmap.putAll(expand);
   }
 }
 /**
  * get types annotated with a given annotation, both classes and annotations, including annotation
  * member values matching
  *
  * <p>{@link Inherited} is honored according to given honorInherited
  *
  * <p>depends on TypeAnnotationsScanner configured
  */
 public Set<Class<?>> getTypesAnnotatedWith(final Annotation annotation, boolean honorInherited) {
   Iterable<String> annotated =
       store.get(index(TypeAnnotationsScanner.class), annotation.annotationType().getName());
   Iterable<Class<?>> filter = filter(forNames(annotated, loaders()), withAnnotation(annotation));
   Iterable<String> classes =
       getAllAnnotated(
           names(filter),
           annotation.annotationType().isAnnotationPresent(Inherited.class),
           honorInherited);
   return Sets.newHashSet(
       concat(filter, forNames(filter(classes, not(in(Sets.newHashSet(annotated)))), loaders())));
 }
 // Loop through all changed classes, adding their parents (and their
 // parents)
 // to another set of changed classes
 public Set<JavaClass> findChangedParents(Set<JavaClass> classes) {
   Set<JavaClass> changedParents = Sets.newHashSet(classes);
   for (JavaClass jclass : classes) {
     findParents(jclass, changedParents);
   }
   return changedParents;
 }
 /**
  * get all fields annotated with a given annotation
  *
  * <p>depends on FieldAnnotationsScanner configured
  */
 public Set<Field> getFieldsAnnotatedWith(final Class<? extends Annotation> annotation) {
   final Set<Field> result = Sets.newHashSet();
   for (String annotated : store.get(index(FieldAnnotationsScanner.class), annotation.getName())) {
     result.add(getFieldFromString(annotated, loaders()));
   }
   return result;
 }
 /**
  * get types annotated with a given annotation, both classes and annotations
  *
  * <p>{@link Inherited} is honored according to given honorInherited.
  *
  * <p>when honoring @Inherited, meta-annotation should only effect annotated super classes and
  * it's sub types
  *
  * <p>when not honoring @Inherited, meta annotation effects all subtypes, including annotations
  * interfaces and classes
  *
  * <p><i>Note that this (@Inherited) meta-annotation type has no effect if the annotated type is
  * used for anything other then a class. Also, this meta-annotation causes annotations to be
  * inherited only from superclasses; annotations on implemented interfaces have no effect.</i>
  *
  * <p>depends on TypeAnnotationsScanner and SubTypesScanner configured
  */
 public Set<Class<?>> getTypesAnnotatedWith(
     final Class<? extends Annotation> annotation, boolean honorInherited) {
   Iterable<String> annotated =
       store.get(index(TypeAnnotationsScanner.class), annotation.getName());
   Iterable<String> classes =
       getAllAnnotated(annotated, annotation.isAnnotationPresent(Inherited.class), honorInherited);
   return Sets.newHashSet(concat(forNames(annotated, loaders()), forNames(classes, loaders())));
 }
 /**
  * get all types scanned. this is effectively similar to getting all subtypes of Object.
  *
  * <p>depends on SubTypesScanner configured with {@code SubTypesScanner(false)}, otherwise {@code
  * ReflectionsException} is thrown
  *
  * <p><i>note using this might be a bad practice. it is better to get types matching some
  * criteria, such as {@link #getSubTypesOf(Class)} or {@link #getTypesAnnotatedWith(Class)}</i>
  *
  * @return Set of String, and not of Class, in order to avoid definition of all types in PermGen
  */
 public Set<String> getAllTypes() {
   Set<String> allTypes =
       Sets.newHashSet(store.getAll(index(SubTypesScanner.class), Object.class.getName()));
   if (allTypes.isEmpty()) {
     throw new ReflectionsException(
         "Couldn't find subtypes of Object. "
             + "Make sure SubTypesScanner initialized to include Object class - new SubTypesScanner(false)");
   }
   return allTypes;
 }
 /**
  * get resources relative paths where simple name (key) matches given namePredicate
  *
  * <p>depends on ResourcesScanner configured
  */
 public Set<String> getResources(final Predicate<String> namePredicate) {
   Iterable<String> resources =
       Iterables.filter(store.get(index(ResourcesScanner.class)).keySet(), namePredicate);
   return Sets.newHashSet(store.get(index(ResourcesScanner.class), resources));
 }
 /**
  * gets all sub types in hierarchy of a given type
  *
  * <p>depends on SubTypesScanner configured
  */
 public <T> Set<Class<? extends T>> getSubTypesOf(final Class<T> type) {
   return Sets.newHashSet(
       ReflectionUtils.<T>forNames(
           store.getAll(index(SubTypesScanner.class), Arrays.asList(type.getName())), loaders()));
 }