Search code examples
spring-bootpf4j

My application can't find the extension with Pf4j


I'm using a Spring Boot application. For now, the use of the plugins is very simple. I'm just following the tutorial. My plugin is started, I'm trying to find the extensions like this:

final List<MyExtensionPoint> sections = pluginManager.getExtensions(MyExtensionPoint.class);

but Pf4j doesn't return the extensions.

When I'm following the code execution, I can see this code in the AbstractExtensionFinder:

if (type.isAssignableFrom(extensionClass)) {
  ExtensionWrapper extensionWrapper = createExtensionWrapper(extensionClass);
  result.add(extensionWrapper);
  log.debug("Added extension '{}' with ordinal {}", className, extensionWrapper.getOrdinal());
} else {
  log.trace("'{}' is not an extension for extension point '{}'", className, type.getName());
  if (RuntimeMode.DEVELOPMENT.equals(pluginManager.getRuntimeMode())) {
    checkDifferentClassLoaders(type, extensionClass);
  }
}

I can understand the program is not entering inside the condition because I have 2 different classloaders: PluginClassLoader (for the extension) and RestartClassLoader (from Spring for the interface of the extension point).

I don't understand why it will be a problem because I think to instanciate the extension class, the PluginClassloader will use the parent class loader (RestartClassLoader) to find the interface.

Where is my mistake ? How to fix it ?

Thank you.


Solution

  • I extended the DevelopmentPluginLoader to pass the Spring classloader.

    public class MyDevelopmentPluginLoader extends DevelopmentPluginLoader {
    
        private ClassLoader parentClassLoader;
    
        /**
         * @param pluginManager
         */
        public MyDevelopmentPluginLoader(final PluginManager pluginManager, final ClassLoader parentClassLoader) {
            super(pluginManager);
            this.parentClassLoader = parentClassLoader;
        }
    
        @Override
        protected PluginClassLoader createPluginClassLoader(final Path pluginPath, final PluginDescriptor pluginDescriptor) {
            return new PluginClassLoader(pluginManager, pluginDescriptor, parentClassLoader);
        }
    }
    
    

    and in my custom PluginManager, I created and instance of my PluginLoader:

    protected PluginLoader createPluginLoader() {
    
            final CompoundPluginLoader compoundPluginLoader = new CompoundPluginLoader();
            final PluginLoader developmentPluginLoader = new MyDevelopmentPluginLoader(this, getClass().getClassLoader());
            final PluginLoader jarPluginLoader = new JarPluginLoader(this);
            final PluginLoader defaultPluginLoader = new DefaultPluginLoader(this);
    
            // @formatter:off
            return compoundPluginLoader.
                    add(developmentPluginLoader, this::isDevelopment).
                    add(jarPluginLoader, this::isNotDevelopment).
                    add(defaultPluginLoader, this::isNotDevelopment);
            // @formatter:on
        }