7

I have selected Apache Commons IO, JSerialComm and Ini4J libraries via Maven repository.

But when I try to create an image via mvn javafx:jlink I get this errors:

[INFO] --- javafx-maven-plugin:0.0.2:jlink (default-cli) @ JUSBPlotter ---
[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: ini4j from file:///root/.m2/repository/org/ini4j/ini4j/0.5.4/ini4j-0.5.4.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:447)

I seems it have something to do with this:

Error: automatic module cannot be used with jlink:

My module file looks like this:

module org.openjfx.JUSBPlotter {
    requires javafx.controls;
    requires javafx.fxml;
    requires com.fazecast.jSerialComm;
    requires ini4j;
    requires org.apache.commons.io;

    opens org.openjfx.JUSBPlotter to javafx.fxml;
    exports org.openjfx.JUSBPlotter;
}

And my pom.xml looks like this:

<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 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.openjfx</groupId>
    <artifactId>JUSBPlotter</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-controls</artifactId>
            <version>11.0.2</version>
        </dependency>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-fxml</artifactId>
            <version>11.0.2</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.6</version>
        </dependency>
        <dependency>
            <groupId>com.fazecast</groupId>
            <artifactId>jSerialComm</artifactId>
            <version>2.5.1</version>
        </dependency>
        <dependency>
            <groupId>org.ini4j</groupId>
            <artifactId>ini4j</artifactId>
            <version>0.5.4</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.0</version>
                <configuration>
                    <release>11</release>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.openjfx</groupId>
                <artifactId>javafx-maven-plugin</artifactId>
                <version>0.0.2</version>
                <configuration>
                    <stripDebug>true</stripDebug>
                    <compress>2</compress>
                    <noHeaderFiles>true</noHeaderFiles>
                    <noManPages>true</noManPages>
                    <launcher>JUSBPlotter</launcher>
                    <jlinkImageName>JUSBPlotter</jlinkImageName>
                    <jlinkZipName>JUSBPlotterZip</jlinkZipName>
                    <mainClass>org.openjfx.JUSBPlotter.Main</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

So can it be that Apache Commons IO, JSerialComm and Ini4J is to old for Maven and Jlink?

How should I solve this problem? I'm using Eclipse IDE with OpenJDK 11.

euraad
  • 2,467
  • 5
  • 30
  • 51
  • 1
    The unfortunate thing about `jlink` is it can only create images when everything is an explicit module (i.e. has a `module-info` file). At least one of your dependencies (`ini4j`) is not an explicit module; see [What is an automatic module?](https://stackoverflow.com/questions/46741907/what-is-an-automatic-module) for more information. You have at least a few options: (1) Modify/fork the dependency to be an explicit module, (2) fallback to the classpath and package your application in a "fat" jar, or (3) try `jpackage` (early-access, I doubt `javafx-maven-plugin` provides support yet). – Slaw May 31 '19 at 13:43
  • @Slaw Option 1 seems to be the right for me. But how? – euraad May 31 '19 at 15:36
  • @Slaw I think I can just copy over the source code from ini4j to my project. It seems to be an easy project. – euraad May 31 '19 at 16:40
  • 1
    Not familiar with it, but [this project](https://github.com/moditect/moditect) may help. – Slaw May 31 '19 at 18:05

1 Answers1

0

The jlink requires all dependencies to be modular. After generation, it generates a custom JRE image including the required modules. The ini4j seems non-modular. For non-modular dependencies, you can go with the old Classpath approach after getting the custom JRE which has been generated without non-modular ones.

Briefly, run jlink excluding the non-modulars than add the jar files of non-modulars to the generated JRE image. The modules method and Classpath method can be combined this way.

A bit of fiddling with maven plugins should do this automatically.

Example for ini4j

  • Define some properties for convenience.

pom.xml

<properties>
    <jlink-image-name>JUSBPlotter</jlink-image-name>
    <ini4j-jar-name>ini4j.jar</ini4j-jar-name>
</properties>
  1. Disable ini4j from module-info.java (It should be enable during development, only do this when you want to package the project)
module org.openjfx.JUSBPlotter {
    requires javafx.controls;
    requires javafx.fxml;
    requires com.fazecast.jSerialComm;
    //requires ini4j;
    requires org.apache.commons.io;

    opens org.openjfx.JUSBPlotter to javafx.fxml;
    exports org.openjfx.JUSBPlotter;
}
  1. Configure maven-dependency-plugin to copy the jar file of ini4j into the lib/ folder in jlink image.
<plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-dependency-plugin</artifactId>
        <executions>
          <execution>
            <id>copy</id>
            <phase>package</phase>
            <goals>
              <goal>copy</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <artifactItems>
            <!-- Copy ini4j jar into the jlink image -->
            <artifactItem>
              <groupId>org.ini4j</groupId>
              <artifactId>ini4j</artifactId>
              <version>0.5.4</version>
              <type>jar</type>
              <destFileName>${ini4j-jar-name}</destFileName>
            </artifactItem>
          </artifactItems>
          <!-- Set output directory to lib folder in jlink image -->
          <outputDirectory>${project.build.directory}/${jlink-image-name}/lib</outputDirectory>
          <overWriteReleases>true</overWriteReleases>
          <overWriteSnapshots>true</overWriteSnapshots>
        </configuration>
</plugin>
  1. Configure jlink launcher option in the javafx-maven-plugin in order to add the jar file of non-modular ini4j to the Classpath.
<plugin>
    <groupId>org.openjfx</groupId>
    <artifactId>javafx-maven-plugin</artifactId>
    <version>0.0.8</version>
    <configuration>
        <stripDebug>true</stripDebug>
        <compress>2</compress>
        <noHeaderFiles>true</noHeaderFiles>
        <noManPages>true</noManPages>
        <launcher>JUSBPlotter</launcher>
        <jlinkImageName>JUSBPlotter</jlinkImageName>
        <mainClass>org.openjfx.JUSBPlotter.Main</mainClass>
        <!-- ini4j jar file will be copied to the {image-folder}/lib/ folder. The launcher script should have this option to add it to the classpath -->
        <options>-cp ../lib/${init4j-jar-name}</options>
    </configuration>
</plugin>

Run:

  • mvn clean javafx:jlink
  • mvn package
  • cd target/JUSBPlotter/bin
  • ./JUSBPlotter

maven-dependeny-plugin will copy the jar file when you run mvn package. But the jlink image must be already generated. So run the mvn javafx:jlink first. Then run mvn package.

Refer here to see how I applied for sqlite-jdbc in my project.

user12043
  • 396
  • 1
  • 3
  • 12
  • Hi, I tried to follow your steps, but i got an error. I have 17 dependencies in module-info.java when i comment out some(1. step) I receive: COMPILATION ERROR (BUILD FAILURE), if I dont comment out them randomly one dependency gives error: `Error: automatic module cannot be used with jlink [ERROR] Command execution failed. org.apache.commons.exec.ExecuteException: Process exited with an error: 1 (Exit value: 1)` May I kindly ask for help? – Thend Jan 16 '23 at 21:29
  • 1
    @Thend Only comment them when you will build the final package. If you follow the answer step-by-step, it should work. – user12043 Feb 19 '23 at 09:54