diff --git a/pom.xml b/pom.xml
index 551f822..873fc67 100644
--- a/pom.xml
+++ b/pom.xml
@@ -54,7 +54,7 @@
3.8.6
11.1.3
7.1.1
- 0.10.2
+ 4.8.179
1.8.2
3.1.0
2.0.3
@@ -76,9 +76,9 @@
- org.reflections
- reflections
- ${version.reflections}
+ io.github.classgraph
+ classgraph
+ ${version.classgraph}
@@ -228,8 +228,8 @@
- org.reflections
- reflections
+ io.github.classgraph
+ classgraph
diff --git a/src/main/java/eu/europa/ted/eforms/sdk/component/SdkComponentFactory.java b/src/main/java/eu/europa/ted/eforms/sdk/component/SdkComponentFactory.java
index 80a3482..2cc9f5e 100644
--- a/src/main/java/eu/europa/ted/eforms/sdk/component/SdkComponentFactory.java
+++ b/src/main/java/eu/europa/ted/eforms/sdk/component/SdkComponentFactory.java
@@ -9,11 +9,9 @@
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Optional;
-import java.util.stream.Stream;
import eu.europa.ted.eforms.sdk.SdkVersion;
-import org.reflections.Reflections;
-import org.reflections.util.ClasspathHelper;
-import org.reflections.util.ConfigurationBuilder;
+import io.github.classgraph.ClassGraph;
+import io.github.classgraph.ScanResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -23,6 +21,26 @@
public abstract class SdkComponentFactory {
private static final Logger logger = LoggerFactory.getLogger(SdkComponentFactory.class);
+ /**
+ * Lazy-init holder for the JVM-wide classpath scan. Triggered the first time any
+ * {@link SdkComponentFactory} subclass is constructed; the resulting list is shared
+ * by all subclasses so that the (potentially expensive) classpath walk runs only once
+ * per JVM rather than once per factory subclass.
+ */
+ private static final class AnnotatedClassesHolder {
+ static final List> CLASSES = scan();
+
+ private static List> scan() {
+ logger.debug("Scanning the classpath for types annotated with {}", SdkComponent.class);
+ try (ScanResult result = new ClassGraph()
+ .enableAnnotationInfo()
+ .ignoreClassVisibility()
+ .scan()) {
+ return result.getClassesWithAnnotation(SdkComponent.class).loadClasses();
+ }
+ }
+ }
+
private Map>> componentsMap;
class ComponentSelector {
@@ -65,67 +83,47 @@ protected SdkComponentFactory() {
private void populateComponents() {
Class annotationType = SdkComponent.class;
- logger.debug("Looking in the classpath for types annotated with {}", annotationType);
-
if (componentsMap == null) {
componentsMap = new HashMap<>();
}
- // Get a list of all the packages loaded by the available classloaders.
- // This can be a bit expensive in some situations, so this method factory should
- // be ensured to run as less as possible (ideally only once).
- String[] availablePackages = Arrays
- .stream(ClasspathHelper.classLoaders())
- .map(ClassLoader::getDefinedPackages)
- .flatMap(Stream::of)
- .map(Package::getName)
- .toArray(String[]::new);
+ AnnotatedClassesHolder.CLASSES.forEach((Class> clazz) -> {
+ logger.trace("Processing type [{}]", clazz);
- if (logger.isTraceEnabled()) {
- final List packages = Arrays.asList(availablePackages);
- packages.stream().sorted()
- .forEach(p -> logger.trace(p));
- }
+ SdkComponent annotation = clazz.getAnnotation(annotationType);
+
+ String[] supportedSdkVersions = annotation.versions();
+ SdkComponentType componentType = annotation.componentType();
+ String qualifier = annotation.qualifier();
+ ComponentSelector selector = new ComponentSelector(componentType, qualifier);
+
+ logger.trace("Class [{}] has a component type of [{}] and supports SDK versions [{}]",
+ clazz, componentType, supportedSdkVersions);
+
+ Arrays.asList(supportedSdkVersions).forEach((String sdkVersion) -> {
+ SdkComponentDescriptor> component =
+ new SdkComponentDescriptor<>(sdkVersion, componentType, clazz);
+
+ Map> components =
+ componentsMap.get(sdkVersion);
+
+ if (components != null) {
+ SdkComponentDescriptor> existingComponent = components.get(selector);
+
+ if (existingComponent != null && !existingComponent.equals(component)) {
+ throw new IllegalArgumentException(MessageFormat.format(
+ "More than one components of type [{0}] have been found for SDK version [{1}]:\n\t- {2}\n\t- {3}",
+ componentType, sdkVersion, existingComponent.getImplType().getName(),
+ clazz.getName()));
+ }
+ } else {
+ components = new HashMap<>();
+ componentsMap.put(sdkVersion, components);
+ }
- new Reflections(ConfigurationBuilder.build().forPackages(availablePackages))
- .getTypesAnnotatedWith(annotationType).stream()
- .forEach((Class> clazz) -> {
- logger.trace("Processing type [{}]", clazz);
-
- SdkComponent annotation = clazz.getAnnotation(annotationType);
-
- String[] supportedSdkVersions = annotation.versions();
- SdkComponentType componentType = annotation.componentType();
- String qualifier = annotation.qualifier();
- ComponentSelector selector = new ComponentSelector(componentType, qualifier);
-
- logger.trace("Class [{}] has a component type of [{}] and supports SDK versions [{}]",
- clazz, componentType, supportedSdkVersions);
-
- Arrays.asList(supportedSdkVersions).forEach((String sdkVersion) -> {
- SdkComponentDescriptor> component =
- new SdkComponentDescriptor<>(sdkVersion, componentType, clazz);
-
- Map> components =
- componentsMap.get(sdkVersion);
-
- if (components != null) {
- SdkComponentDescriptor> existingComponent = components.get(selector);
-
- if (existingComponent != null && !existingComponent.equals(component)) {
- throw new IllegalArgumentException(MessageFormat.format(
- "More than one components of type [{0}] have been found for SDK version [{1}]:\n\t- {2}\n\t- {3}",
- componentType, sdkVersion, existingComponent.getImplType().getName(),
- clazz.getName()));
- }
- } else {
- components = new HashMap<>();
- componentsMap.put(sdkVersion, components);
- }
-
- components.put(selector, component);
- });
- });
+ components.put(selector, component);
+ });
+ });
}
protected T getComponentImpl(String sdkVersion, final SdkComponentType componentType,