From 48495e024d6afd332119a6c6b345cee7ec47fb2e Mon Sep 17 00:00:00 2001 From: Andrea Di Cesare Date: Wed, 7 Feb 2024 10:35:58 +0100 Subject: [PATCH] :bug: Fix ClassNotFoundException when a Provider attempted to provide an instance of a class located within plugin JAR files --- .../org/restheart/plugins/PluginsScanner.java | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/restheart/plugins/PluginsScanner.java b/core/src/main/java/org/restheart/plugins/PluginsScanner.java index 97c99c2674..cf0b05a2cb 100644 --- a/core/src/main/java/org/restheart/plugins/PluginsScanner.java +++ b/core/src/main/java/org/restheart/plugins/PluginsScanner.java @@ -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; @@ -299,7 +300,7 @@ private static ArrayList 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 @@ -311,6 +312,39 @@ private static ArrayList collectFieldInjections(ClassInfo p return ret; } + private static ArrayList _classLoaders = null; + + /** + * Loads a class, including searching within all plugin JAR files. + *

+ * 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. + *

+ */ + 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