Add module descriptor to library with JavaFX and maven [duplicate]
Asked Answered
V

1

5

I need to use Reflections in a maven project with JavaFX and I want to use jlink to bundle a minimal JRE.

The problem is that I get the following error when running mvn clean compile javafx:jlink:

[WARNING] Required filename-based automodules detected. Please don't publish this project to a public artifact repository!
Error: automatic module cannot be used with jlink: reflections from file:///C:/Users/Daniel/.m2/repository/org/reflections/reflections/0.9.12/reflections-0.9.12.jar
[ERROR] Command execution failed.
org.apache.commons.exec.ExecuteException: Process exited with an error: 1 (Exit value: 1)
    at org.apache.commons.exec.DefaultExecutor.executeInternal (DefaultExecutor.java:404)
    at org.apache.commons.exec.DefaultExecutor.execute (DefaultExecutor.java:166)
    at org.openjfx.JavaFXBaseMojo.executeCommandLine (JavaFXBaseMojo.java:504)
    at org.openjfx.JavaFXBaseMojo.executeCommandLine (JavaFXBaseMojo.java:394)
    at org.openjfx.JavaFXJLinkMojo.execute (JavaFXJLinkMojo.java:187)
    at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo (DefaultBuildPluginManager.java:137)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:210)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:156)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:148)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:117)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:81)
    at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build (SingleThreadedBuilder.java:56)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.execute (LifecycleStarter.java:128)
    at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:305)
    at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:192)
    at org.apache.maven.DefaultMaven.execute (DefaultMaven.java:105)
    at org.apache.maven.cli.MavenCli.execute (MavenCli.java:957)
    at org.apache.maven.cli.MavenCli.doMain (MavenCli.java:289)
    at org.apache.maven.cli.MavenCli.main (MavenCli.java:193)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62)
    at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke (Method.java:564)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced (Launcher.java:282)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launch (Launcher.java:225)
    at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode (Launcher.java:406)
    at org.codehaus.plexus.classworlds.launcher.Launcher.main (Launcher.java:347)
org.apache.commons.exec.ExecuteException: Process exited with an error: 1 (Exit value: 1)
        at org.apache.commons.exec.DefaultExecutor.executeInternal(DefaultExecutor.java:404)
        at org.apache.commons.exec.DefaultExecutor.execute(DefaultExecutor.java:166)
        at org.openjfx.JavaFXBaseMojo.executeCommandLine(JavaFXBaseMojo.java:504)
        at org.openjfx.JavaFXBaseMojo.executeCommandLine(JavaFXBaseMojo.java:394)
        at org.openjfx.JavaFXJLinkMojo.execute(JavaFXJLinkMojo.java:187)
        at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:137)
        at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:210)
        at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:156)
        at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:148)
        at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:117)
        at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:81)
        at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:56)
        at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:128)
        at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:305)
        at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:192)
        at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:105)
        at org.apache.maven.cli.MavenCli.execute(MavenCli.java:957)
        at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:289)
        at org.apache.maven.cli.MavenCli.main(MavenCli.java:193)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:564)
        at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:282)
        at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:225)
        at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:406)
        at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:347)

The problem is that Reflections do not support JPMS and jlink requires explicit modules only.

I have seen this answer that describes how to convert an external JAR to a module but I need to do this automatically in my maven build before running jlink.

I also came across moditect that allows exactly this but I did not made that work in my project as I do not know how to tell javafx:jlink to use the converted JAR of the Reflections-library

I could also imagine to use the exec-maven-plugin to run the jlink command but I do not know how to tell the javafx-maven-plugin to take that while not modifying the local repository.

How can I use the jlink-goal of the javafx-maven-plugin while having an automated module (Reflections) as a dependency?


My module-info.java looks like this (simplified):

module my.project{
    exports my.project.toscan to reflections;
    exports my.project.ui to javafx.graphics;
    opens my.project.ui.controllers to javafx.fxml;
    requires javafx.controls;
    requires javafx.fxml;
    requires transitive javafx.graphics;
    requires javafx.base;
    requires reflections;
}

and this is my pom.xml (also simplfied):

<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>my</groupId>
    <artifactId>project</artifactId>
    <version>myversion</version>
    <dependencies>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-controls</artifactId>
            <version>14</version>
        </dependency>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-fxml</artifactId>
            <version>14</version>
        </dependency>
        <dependency>
            <groupId>org.reflections</groupId>
            <artifactId>reflections</artifactId>
            <version>0.9.12</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.0</version>
                <configuration>
                    <release>14</release>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.openjfx</groupId>
                <artifactId>javafx-maven-plugin</artifactId>
                <version>0.0.4</version>
                <configuration>
                    <source>14</source>
                    <target>14</target>
                    <release>14</release>
                    <mainClass>my.project.MainClass</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
Vassar answered 16/3, 2021 at 7:18 Comment(2)
If you were using Gradle I'd suggest The Badass JLink Plugin. I don't know if there's a Maven equivalent.Schlueter
The maven-jlink-plugin exists - I will look into that but I am not sure how well it integrates with JavaFX.Vassar
H
0

Why do you insist on spcifically using this tool chain? You can make use of jlink to create a JavaFX program without having to modularize everything first. Perhaps you can follow the route I have described with Dirk here: https://github.com/dlemmermann/JPackageScriptFX The benefits are basically the same and I don't see any additional benefit of using jlink for the whole application.

Hindustani answered 17/4, 2021 at 14:29 Comment(7)
I want to use modules for my application in general.Vassar
Have fun. I hope you know that you cannot automagically transform an existing jar to a module. For some this works, for others it doesn't.Hindustani
Isn't it possible to use --path-module for that?Vassar
You meant --patch-module, right? Sometimes you can fix a problem with that but I would avoid that route if possible and it also does not always help. Modules have to follow certain rules and often you simply have to refactor your codebase to make them valid. That's not something which any tool could do automagically.Hindustani
Yes, I meant that. The problem I have is that reflections is not modularized and I want to use jlink with it (while still making my application modularized).Vassar
As far as I have seen Reflections is written for Java 8 and due to its nature probably does a lot of nasty things. I doubt that this could run on Java 9+. E.g. how should it deal with the module path when this did not even exist in Java 8.Hindustani
Reflections works sufficiently well for my case (even when using modules). The problem is just that it uses an automated module and my idea was to "patch" that so it automatically creates a module-info.java and inserts that.Vassar

© 2022 - 2024 — McMap. All rights reserved.