beryx/badass-jlink-plugin

Enhancement: Infer module path

oliver-brm opened this issue · 4 comments

In my application, I'm using service modules and separate modules which provide those services. Gradle 7.2 itself is able to infer the module path for the application by looking at the dependencies - service implementations show up as runtime project(...) dependencies. Example:

dependencies {
    implementation project(':greeting-service')        // this is the service API
    runtimeOnly project(':greeting-provider-fixed')  // this is the service implementation
}

I'm using the badass-jlink-plugin:2.24.2, which however does not infer the module path for those service implementations. It's working fine if I specify the module path in a customImage declaration. Example:

jlink {
    customImage {
        appModules = [
                'org.example.jpms.hello.main',
                'org.example.jpms.hello.greeting.service',
                'org.example.jpms.hello.greeting.provider.fixed']
    }
}

This can get a bit cumbersome with more and more modules added to the application. Wouldn't it be possible to derive the module path from the application's dependencies? I would be glad to contribute to that feature.

I have pushed a reproducer project here: https://github.com/oliver-brm/jpms-hello.git. To reproduce:

  1. Remove the customImage declaration from build.gradle
  2. Run the jlink or jpackage task
  3. Try to execute build/image/bin/greeting, it will print:
Exception in thread "main" java.util.NoSuchElementException: No value present
	at java.base/java.util.Optional.orElseThrow(Unknown Source)
	at org.example.jpms.hello.main/org.example.jpms.hello.App.main(Unknown Source)

Sorry for the late reply. It would be great if you can contribute to this feature, it's very useful. Thank you for your help!

OK, cool! I would look if I can somehow extract the module path which the java plugin creates. That would make life a bit easier and it's more predictable for the user what the module path will be. I've never created a plugin for Gradle, nor modified one. So, I'm very happy for any hint how I might start this one.

I sent my message yesterday without having a look at your reproducer project. Now I finally took the time to look at it and realized that I had misunderstood the problem.
There is probably no need to enhance the plugin because jlink itself is able to infer the module path for service implementations when called with the --bind-services option. So, by putting the following in your build.gradle, your application should work fine:

jlink {
    options = ['--bind-services', '--strip-debug', '--compress', '2', '--no-header-files', '--no-man-pages']
    launcher {
        name = 'greeting'
    }
}

Yeah, jlink's --bind-services option - its implementation is in my eyes too greedy. It will pull in any implementing module, not only those which I put on the module path via Gradle's dependency mechanism. See also this thread on Stack Overflow.