Skip to content

Commit

Permalink
🐛 Fix ClassNotFoundException when a Provider attempted to provide an …
Browse files Browse the repository at this point in the history
…instance of a class located within plugin JAR files
  • Loading branch information
ujibang committed Feb 7, 2024
1 parent 96b512a commit 48495e0
Showing 1 changed file with 35 additions and 1 deletion.
36 changes: 35 additions & 1 deletion core/src/main/java/org/restheart/plugins/PluginsScanner.java
Expand Up @@ -45,6 +45,7 @@
import java.util.stream.Collectors;
import java.util.AbstractMap;

import org.checkerframework.common.returnsreceiver.qual.This;
import org.restheart.Bootstrapper;
import org.restheart.graal.NativeImageBuildTimeChecker;
import org.restheart.plugins.security.AuthMechanism;
Expand Down Expand Up @@ -299,7 +300,7 @@ private static ArrayList<InjectionDescriptor> collectFieldInjections(ClassInfo p
}

try {
var fieldClass = Class.forName(fi.getTypeDescriptor().toString(), false, PluginsScanner.class.getClassLoader());
var fieldClass = loadClass(fi.getTypeDescriptor().toString());
ret.add(new FieldInjectionDescriptor(fi.getName(), fieldClass, annotationParams, fi.hashCode()));
} catch(ClassNotFoundException cnfe) {
// should not happen
Expand All @@ -311,6 +312,39 @@ private static ArrayList<InjectionDescriptor> collectFieldInjections(ClassInfo p
return ret;
}

private static ArrayList<ClassLoader> _classLoaders = null;

/**
* Loads a class, including searching within all plugin JAR files.
* <p>
* This method is essential for the {@code collectFieldInjections()} method, which processes field injections
* annotated with {@code @Inject}. Specifically, it addresses cases where the {@code @Inject} annotation
* references a {@link org.restheart.plugins.Provider} that returns an object. The class of this object may reside
* in a plugin JAR file, necessitating a comprehensive search to locate and load the class correctly.
* </p>
*/
private static Class<?> loadClass(String clazz) throws ClassNotFoundException {
if (_classLoaders == null || _classLoaders.isEmpty()) {
_classLoaders = new ArrayList<>();
_classLoaders.add(PluginsScanner.class.getClassLoader());

// take all classloaders into account to search also within all plugin JAR files
if (PluginsScanner.jars != null) {
_classLoaders.add(new URLClassLoader(PluginsScanner.jars));
}
}

for (var classLoader: _classLoaders) {
try {
return Class.forName(clazz, false, classLoader);
} catch (ClassNotFoundException cnfe) {
// nothing to do
}
}

throw new ClassNotFoundException("plugin class not found " + clazz);
}

/**
* this removes the reference to scanResult in the annotation info
* otherwise the huge object won't be garbage collected
Expand Down

0 comments on commit 48495e0

Please sign in to comment.