Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ServiceLoader based on module-info.java not working #7634

Open
codepitbull opened this issue Oct 19, 2023 · 10 comments
Open

ServiceLoader based on module-info.java not working #7634

codepitbull opened this issue Oct 19, 2023 · 10 comments
Assignees

Comments

@codepitbull
Copy link

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
@hamzaGhaissi
Copy link
Member

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

@codepitbull
Copy link
Author

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: #4141

So, is JPMS not fully supported on Graal?
Do you have any pointers where this might be documented?

@hamzaGhaissi hamzaGhaissi self-assigned this Oct 24, 2023
@hamzaGhaissi
Copy link
Member

Thanks, Issue reproduced and we are looking into it

@hamzaGhaissi hamzaGhaissi assigned wirthi and olpaw and unassigned wirthi Oct 24, 2023
@hamzaGhaissi hamzaGhaissi removed their assignment Jan 29, 2024
@PeteSL
Copy link

PeteSL commented Mar 11, 2024

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.

@SentryMan
Copy link

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?

@agentgt
Copy link

agentgt commented Sep 24, 2024

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.

@Mechite
Copy link

Mechite commented Sep 24, 2024

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.

@olpaw
Copy link
Member

olpaw commented Oct 28, 2024

Hi @codepitbull,

thanks for your reproducer. I have looked into the issue and we now know where the problem is.
#9952 (comment)

I will keep you updated.

@olpaw
Copy link
Member

olpaw commented Oct 28, 2024

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 #9952 (comment) for more info.

@ivan-ristovic
Copy link
Contributor

Hi @codepitbull! The fix that relates to this ticket has been merged (#10202) and will be part of GraalVM 24.2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants