Menu

#204 Java ServiceLoader.load() doesn't find any implementations

All
open
nobody
None
5
2023-12-22
2023-11-02
Tim Wundke
No

I have an application running on Java 11 in Windows 10, and I have tried to turn it into a Windows service using yajsw 13.10.

My application attempts to load various plugins at startup using java.util.ServiceLoader.load(MyInterface.class). It also uses JPMS, so the services are defined in the module-info.java files using uses MyInterface and provides MyInterface with MyInterfaceImpl.

When I run the application via yajsw (using runConsole.bat), the application is started ok, but the service loader returns no implementations, hence the application ends up with no plugins.

The modules are defined in the wrapper.conf file as

wrapper.java.app.module-path.1 = ./lib
wrapper.java.app.module-path.2 = ./plugins
...

I have debugged essentially the whole lifecycle, and can see that the modules are correctly found and are passed through to WrapperJVMMain9, but somehow this isn't correctly flowing through to my application.

Just as extra information, I use an iterator to find the loaded services, and ServiceLoader.iterator() creates an internal ModuleServicesLookupIterator. In hasNext(), this ends up calling ServicesCatalog.getServicesCatalogOrNull(ClassLoader), and this returns null. This seems to be the crux of the problem.

Hopefully this all makes sense!

Discussion

  • rzo

    rzo - 2023-11-03

    Hello,
    thanks for reporting the issue.
    Could you pls provide some more details on how your application is built, or better a reproducer.
    In the mean time I will try to reproduce the issue.
    I assume that this may be a classloader issue.

    -- ron

     
  • Tim Wundke

    Tim Wundke - 2023-11-09

    Hi Ron,
    I've included a small maven-built application that reproduces the problem. You should be able to just run mvn compile in the example-application directory, then run it using the following command:

    java -p "./application/target/classes;./plugin-api/target/classes;./plugin-impl/target/classes" -m application/org.example.application.Application
    

    If the application finds a plugin, which it should using the above command, it will output the plugin's name, then sleep for 60 seconds, simulating it doing something.

    If no plugin is found (just remove the plugin-impl path), it'll indicate that, then exit immediately.

    I've included a wrapper.conf file in the root directory. Just replace the paths indicated, and use runConsole.bat. It should print that no plugins were found, and exit immediately.

    Hope that helps.

    Tim

     
  • rzo

    rzo - 2023-11-29

    thanks a ton for providing the reproducer.
    i am currently very busy with other work.
    i will get to it asap.

    -- Ron

     
  • rzo

    rzo - 2023-12-22

    pls try the following:
    remove:

    wrapper.java.app.module = application

    add:

    wrapper.java.additional.1=--add-modules
    wrapper.java.additional.2=application
    wrapper.java.additional.3=-p
    wrapper.java.additional.4=./application/target/classes;./plugin-api/target/classes;./plugin-impl/target/classes

    it works for me with the example.

    -- Ron

     

Log in to post a comment.