Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make usage of ClassGraphFacade replacable with custom logic in ReflectionUtils #491

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@

import java.util.Collections;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

import io.github.classgraph.ClassGraph;
import io.github.classgraph.ClassInfoList;
Expand All @@ -37,22 +36,11 @@
*
* @author Pascal Schumacher (https://github.com/PascalSchumacher)
*/
abstract class ClassGraphFacade {
class ClassGraphFacade {

private static final ConcurrentHashMap<Class<?>, List<Class<?>>> typeToConcreteSubTypes = new ConcurrentHashMap<>();
private static final ScanResult scanResult = new ClassGraph().enableSystemJarsAndModules().enableClassInfo().scan();
private final static ScanResult scanResult = new ClassGraph().enableSystemJarsAndModules().enableClassInfo().scan();

/**
* Searches the classpath for all public concrete subtypes of the given interface or abstract class.
*
* @param type to search concrete subtypes of
* @return a list of all concrete subtypes found
*/
public static <T> List<Class<?>> getPublicConcreteSubTypesOf(final Class<T> type) {
return typeToConcreteSubTypes.computeIfAbsent(type, ClassGraphFacade::searchForPublicConcreteSubTypesOf);
}

private static <T> List<Class<?>> searchForPublicConcreteSubTypesOf(final Class<T> type) {
static List<Class<?>> searchForPublicConcreteSubTypesOf(final Class<?> type) {
String typeName = type.getName();
ClassInfoList subTypes = type.isInterface() ? scanResult.getClassesImplementing(typeName) : scanResult.getSubclasses(typeName);
List<Class<?>> loadedSubTypes = subTypes.filter(subType -> subType.isPublic() && !subType.isAbstract()).loadClasses(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import java.lang.reflect.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Stream;

Expand All @@ -52,6 +53,11 @@
*/
public final class ReflectionUtils {

private static final ConcurrentHashMap<Class<?>, List<Class<?>>> typeToConcreteSubTypes = new ConcurrentHashMap<>();

// NOTE: indirection to avoid loading ClassGraphFacade class too early
private static volatile Function<Class<?>, List<Class<?>>> typeToConcreteSubTypesProvider = ReflectionUtils::defaultTypeToConcreteSubTypesProvider;

private ReflectionUtils() {
}

Expand Down Expand Up @@ -402,7 +408,25 @@ public static boolean isTypeVariable(final Type type) {
* @return a list of all concrete subtypes found
*/
public static <T> List<Class<?>> getPublicConcreteSubTypesOf(final Class<T> type) {
return ClassGraphFacade.getPublicConcreteSubTypesOf(type);
return typeToConcreteSubTypes.computeIfAbsent(type, typeToConcreteSubTypesProvider);
}

/**
* Override the default implementation of ClassGraphFacade for searching the
* classpath for any concrete subtype of given interface or abstract class.
*
* @param typeToConcreteSubTypesProvider custom implementation
*/
public static void setPublicConcreteSubTypeProvider(
final Function<Class<?>, List<Class<?>>> typeToConcreteSubTypesProvider) {
if (typeToConcreteSubTypesProvider == null) {
throw new IllegalArgumentException();
}
ReflectionUtils.typeToConcreteSubTypesProvider = typeToConcreteSubTypesProvider;
}

private static List<Class<?>> defaultTypeToConcreteSubTypesProvider(final Class<?> cls) {
return ClassGraphFacade.searchForPublicConcreteSubTypesOf(cls);
}

/**
Expand Down