graal
graal copied to clipboard
ServiceLoader based on module-info.java not working
Describe the issue I am currently experimenting with JPMS on Java 21 and GraalVM.
I discovered using services defined in a different module than the main one aren't picked up.
Steps to reproduce the issue
Clone the reproducer: git clone --depth 1 https://github.com/codepitbull/graalvm-bug-java21.git
There is an app module with a dependency on the dependency module defined:
module javatest.app.main {
requires javatest.dependency.main;
uses MyService;
}
The dependency defines the interface and the service implementation:
module javatest.dependency.main {
exports de.codepitbull.module.example;
provides MyService with de.codepitbull.module.example.MyServiceImpl;
}
The expctation would be that the app sees the defined service when a native image is built.
Build java only
- Run
./gradlew :app:build - Run the application: `java --module-path ./app/build/libs/app.jar:./dependency/build/libs/dependency.jar -m javatest.app.main/java21.App``
Output:
Found a service: MyService!
Called Dependency.hello()
This shows the service is discovered running regular Java.
Build with native-image
- Run
./gradlew :app:nativeBuild - Run the app
app/build/native/nativeBuild/app
Output:
Called Dependency.hello()
This shows that the service is not discovered when using the native build.
Build image natively (to avoid possible Gradle-plugin issues)
- Run `native-image --module-path ./app/build/libs/app.jar:./dependency/build/libs/dependency.jar --module javatest.dependency.main -m javatest.app.main/java21.App``
- Run app `java21.app``
Output:
Called Dependency.hello()
Again, service not resolved.
Describe GraalVM and your environment:
- GraalVM version:
native-image 21 2023-09-19
GraalVM Runtime Environment GraalVM CE 21+35.1 (build 21+35-jvmci-23.1-b15)
Substrate VM GraalVM CE 21+35.1 (build 21+35, serial gc)
- JDK major version:
openjdk version "21" 2023-09-19
OpenJDK Runtime Environment GraalVM CE 21+35.1 (build 21+35-jvmci-23.1-b15)
OpenJDK 64-Bit Server VM GraalVM CE 21+35.1 (build 21+35-jvmci-23.1-b15, mixed mode, sharing)
- OS: 13.5.1 (22G90)
- Architecture: Applie Silicon M2
Hi @codepitbull ,
You need to register the service interface so that the ServiceLoader can identify and load them. The configuration files need to be created in the folder META-INF/services.
In order to resolve the issue create a sub directories inside the dependency folder like this
dependency/src/main/resources/META-INF/services
and inside the services folder create a file named de.codepitbull.module.example.MyService, that file will have all the implementation of that service (one in each line) in this case only 1 like this
de.codepitbull.module.example.MyServiceImpl
Thanks for your answer!
I am aware of the old way, but I was looking at doing this using JPMS. According to this issue it is supposed to work: https://github.com/oracle/graal/issues/4141
So, is JPMS not fully supported on Graal? Do you have any pointers where this might be documented?
Thanks, Issue reproduced and we are looking into it
With 21.0.2, even if the META-INF/services files are there, they are not recognized and ServiceLoader does not work. JVMs work fine, native-image only works using classpath instead of module-path.
even if the META-INF/services files are there, they are not recognized and ServiceLoader does not work. JVMs work fine, native-image only works using classpath instead of module-path.
I am also seeing this issue, has any progress been made?
Yes this seems like it is pretty bad and hurts module-info uptake.
Someone developing a CLI might want to have a JLink option which would use the modulepath and then a native option for supported platforms and they would have to run it on the classpath which would actually change behavior.
~~https://github.com/Mechite/test-graal-nativeimage~~ ~~Created a test repository which was used to demonstrate~~ EDIT - No need for one to use my repository, one above can also be used for reproducing what I have stated below the same:
Older version of GraalVM (CE 11) is able to successfully produce a native image, where services defined in a module-info are correctly read and loaded, without META-INF/services
Newer version (latest current Oracle GraalVM 21 as of 24/09/2024) produces an image that does not discover the services.
I have not checked which release of GraalVM has actually broken this behaviour.
Hi @codepitbull,
thanks for your reproducer. I have looked into the issue and we now know where the problem is. https://github.com/oracle/graal/issues/9952#issuecomment-2442086616
I will keep you updated.
Older version of GraalVM (CE 11) is able to successfully produce a native image, where services defined in a module-info are correctly read and loaded, without META-INF/services
Yes, exploiting the LazyClassPathLookupIterator at image-runtime to do the lookup worked until we actually started to implement module-system more correctly at image runtime. Now that we do, LazyClassPathLookupIterator is able to detect that it is actually not supposed to do the lookup for a Service Provider implementation Class that comes from a named module. So the hack from back then does not work anymore. See https://github.com/oracle/graal/issues/9952#issuecomment-2442086616 for more info.
Hi @codepitbull! The fix that relates to this ticket has been merged (#10202) and will be part of GraalVM 24.2