I am using JavaFX and have some dependencies that are not automatic modules. When trying to run mvn clean javafx:jlink
I get the following error:
Error: automatic module cannot be used with jlink: org.apache.commons.io from [...]`
This also errored for org.apache.commons.commons-lang3
and commons-codec.commons-codec
. Which error I was shown was random.
So I looked into using jdeps to generate a module info for the dependency, e.g.
jdeps --generate-module-info tmp .../.m2/repository/commons-io/commons-io/2.12.0/commons-io-2.12.0.jar
Then I used Moditect to add the module-info to the existing jar:
<plugin>
<groupId>org.moditect</groupId>
<artifactId>moditect-maven-plugin</artifactId>
<version>1.0.0.Final</version>
<executions>
<execution>
<id>add-module-infos</id>
<phase>generate-resources</phase>
<goals>
<goal>add-module-info</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/modules</outputDirectory>
<modules>
<module>
<artifact>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.12.0</version>
</artifact>
<moduleInfoSource>
module org.apache.commons.io {
exports org.apache.commons.io;
exports org.apache.commons.io.build;
exports org.apache.commons.io.charset;
exports org.apache.commons.io.comparator;
exports org.apache.commons.io.file;
exports org.apache.commons.io.file.attribute;
exports org.apache.commons.io.file.spi;
exports org.apache.commons.io.filefilter;
exports org.apache.commons.io.function;
exports org.apache.commons.io.input;
exports org.apache.commons.io.input.buffer;
exports org.apache.commons.io.monitor;
exports org.apache.commons.io.output;
exports org.apache.commons.io.serialization;
}
</moduleInfoSource>
</module>
<module>
<artifact>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</artifact>
<moduleInfoSource>
module org.apache.commons.lang3 {
requires transitive java.desktop;
exports org.apache.commons.lang3;
exports org.apache.commons.lang3.arch;
exports org.apache.commons.lang3.builder;
exports org.apache.commons.lang3.compare;
exports org.apache.commons.lang3.concurrent;
exports org.apache.commons.lang3.concurrent.locks;
exports org.apache.commons.lang3.event;
exports org.apache.commons.lang3.exception;
exports org.apache.commons.lang3.function;
exports org.apache.commons.lang3.math;
exports org.apache.commons.lang3.mutable;
exports org.apache.commons.lang3.reflect;
exports org.apache.commons.lang3.stream;
exports org.apache.commons.lang3.text;
exports org.apache.commons.lang3.text.translate;
exports org.apache.commons.lang3.time;
exports org.apache.commons.lang3.tuple;
}
</moduleInfoSource>
</module>
<module>
<artifact>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.15</version>
</artifact>
<moduleInfoSource>
module org.apache.commons.codec {
exports org.apache.commons.codec;
exports org.apache.commons.codec.binary;
exports org.apache.commons.codec.cli;
exports org.apache.commons.codec.digest;
exports org.apache.commons.codec.language;
exports org.apache.commons.codec.language.bm;
exports org.apache.commons.codec.net;
}
</moduleInfoSource>
</module>
</modules>
</configuration>
</execution>
</executions>
</plugin>
But I am still getting the same errors.
My module-info:
module uk.co.conoregan.showrenamer {
requires info.movito.themoviedbapi;
requires java.prefs;
requires javafx.fxml;
requires javafx.controls;
requires org.apache.commons.io;
requires org.slf4j;
opens uk.co.conoregan.showrenamer to javafx.fxml, javafx.graphics;
opens uk.co.conoregan.showrenamer.controller to javafx.fxml;
exports uk.co.conoregan.showrenamer;
exports uk.co.conoregan.showrenamer.api;
exports uk.co.conoregan.showrenamer.config.preference;
exports uk.co.conoregan.showrenamer.config.property;
exports uk.co.conoregan.showrenamer.controller;
exports uk.co.conoregan.showrenamer.suggestion;
exports uk.co.conoregan.showrenamer.util;
}
My full pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<name>ShowRenamer</name>
<groupId>uk.co.conoregan.show-renamer</groupId>
<artifactId>show-renamer</artifactId>
<version>1.4.0</version>
<properties>
<maven.compiler.java.version>17</maven.compiler.java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<junit.version>5.9.3</junit.version>
<javafx.version>20.0.1</javafx.version>
<slf4j.version>2.0.7</slf4j.version>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-simple -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>${slf4j.version}</version>
<scope>runtime</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mockito/mockito-core -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.3.1</version>
<scope>test</scope>
</dependency>
<!-- JavaFX -->
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>${javafx.version}</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>${javafx.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.12.0</version>
</dependency>
<!-- https://search.maven.org/artifact/com.github.holgerbrandl/themoviedbapi -->
<dependency>
<groupId>com.github.holgerbrandl</groupId>
<artifactId>themoviedbapi</artifactId>
<version>1.15</version>
</dependency>
</dependencies>
<build>
<testResources>
<testResource>
<directory>${project.basedir}/src/test/resources</directory>
</testResource>
</testResources>
<plugins>
<plugin>
<groupId>org.moditect</groupId>
<artifactId>moditect-maven-plugin</artifactId>
<version>1.0.0.Final</version>
<executions>
<execution>
<id>add-module-infos</id>
<phase>generate-resources</phase>
<goals>
<goal>add-module-info</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/modules</outputDirectory>
<modules>
<module>
<artifact>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.12.0</version>
</artifact>
<moduleInfoSource>
module org.apache.commons.io {
exports org.apache.commons.io;
exports org.apache.commons.io.build;
exports org.apache.commons.io.charset;
exports org.apache.commons.io.comparator;
exports org.apache.commons.io.file;
exports org.apache.commons.io.file.attribute;
exports org.apache.commons.io.file.spi;
exports org.apache.commons.io.filefilter;
exports org.apache.commons.io.function;
exports org.apache.commons.io.input;
exports org.apache.commons.io.input.buffer;
exports org.apache.commons.io.monitor;
exports org.apache.commons.io.output;
exports org.apache.commons.io.serialization;
}
</moduleInfoSource>
</module>
<module>
<artifact>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</artifact>
<moduleInfoSource>
module org.apache.commons.lang3 {
requires transitive java.desktop;
exports org.apache.commons.lang3;
exports org.apache.commons.lang3.arch;
exports org.apache.commons.lang3.builder;
exports org.apache.commons.lang3.compare;
exports org.apache.commons.lang3.concurrent;
exports org.apache.commons.lang3.concurrent.locks;
exports org.apache.commons.lang3.event;
exports org.apache.commons.lang3.exception;
exports org.apache.commons.lang3.function;
exports org.apache.commons.lang3.math;
exports org.apache.commons.lang3.mutable;
exports org.apache.commons.lang3.reflect;
exports org.apache.commons.lang3.stream;
exports org.apache.commons.lang3.text;
exports org.apache.commons.lang3.text.translate;
exports org.apache.commons.lang3.time;
exports org.apache.commons.lang3.tuple;
}
</moduleInfoSource>
</module>
<module>
<artifact>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.15</version>
</artifact>
<moduleInfoSource>
module org.apache.commons.codec {
exports org.apache.commons.codec;
exports org.apache.commons.codec.binary;
exports org.apache.commons.codec.cli;
exports org.apache.commons.codec.digest;
exports org.apache.commons.codec.language;
exports org.apache.commons.codec.language.bm;
exports org.apache.commons.codec.net;
}
</moduleInfoSource>
</module>
</modules>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>${maven.compiler.java.version}</source>
<target>${maven.compiler.java.version}</target>
<release>${maven.compiler.java.version}</release>
</configuration>
</plugin>
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.8</version>
<executions>
<execution>
<!-- Default configuration for running with: mvn clean javafx:run -->
<id>default-cli</id>
<configuration>
<mainClass>uk.co.conoregan.showrenamer/uk.co.conoregan.showrenamer.ShowRenamerApplication</mainClass>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
I also ran mvn dependency:tree
to generate the following:
[INFO] uk.co.conoregan.show-renamer:show-renamer:jar:1.4.0
[INFO] +- org.slf4j:slf4j-api:jar:2.0.7:compile
[INFO] +- org.slf4j:slf4j-simple:jar:2.0.7:runtime
[INFO] +- org.junit.jupiter:junit-jupiter-api:jar:5.9.3:test
[INFO] | +- org.opentest4j:opentest4j:jar:1.2.0:test
[INFO] | +- org.junit.platform:junit-platform-commons:jar:1.9.3:test
[INFO] | \- org.apiguardian:apiguardian-api:jar:1.1.2:test
[INFO] +- org.junit.jupiter:junit-jupiter-engine:jar:5.9.3:test
[INFO] | \- org.junit.platform:junit-platform-engine:jar:1.9.3:test
[INFO] +- org.mockito:mockito-core:jar:5.3.1:test
[INFO] | +- net.bytebuddy:byte-buddy:jar:1.14.4:test
[INFO] | +- net.bytebuddy:byte-buddy-agent:jar:1.14.4:test
[INFO] | \- org.objenesis:objenesis:jar:3.3:test
[INFO] +- org.openjfx:javafx-controls:jar:20.0.1:compile
[INFO] | +- org.openjfx:javafx-controls:jar:win:20.0.1:compile
[INFO] | \- org.openjfx:javafx-graphics:jar:20.0.1:compile
[INFO] | +- org.openjfx:javafx-graphics:jar:win:20.0.1:compile
[INFO] | \- org.openjfx:javafx-base:jar:20.0.1:compile
[INFO] | \- org.openjfx:javafx-base:jar:win:20.0.1:compile
[INFO] +- org.openjfx:javafx-fxml:jar:20.0.1:compile
[INFO] | \- org.openjfx:javafx-fxml:jar:win:20.0.1:compile
[INFO] +- commons-io:commons-io:jar:2.12.0:compile
[INFO] \- com.github.holgerbrandl:themoviedbapi:jar:1.15:compile
[INFO] +- org.slf4j:jcl-over-slf4j:jar:2.0.7:runtime
[INFO] +- com.fasterxml.jackson.core:jackson-annotations:jar:2.15.0:runtime
[INFO] +- com.fasterxml.jackson.core:jackson-core:jar:2.15.0:runtime
[INFO] +- com.fasterxml.jackson.core:jackson-databind:jar:2.15.0:runtime
[INFO] +- com.google.guava:guava:jar:31.1-jre:runtime
[INFO] | +- com.google.guava:failureaccess:jar:1.0.1:runtime
[INFO] | +- com.google.guava:listenablefuture:jar:9999.0-empty-to-avoid-conflict-with-guava:runtime
[INFO] | +- com.google.code.findbugs:jsr305:jar:3.0.2:runtime
[INFO] | +- org.checkerframework:checker-qual:jar:3.12.0:runtime
[INFO] | +- com.google.errorprone:error_prone_annotations:jar:2.11.0:runtime
[INFO] | \- com.google.j2objc:j2objc-annotations:jar:1.3:runtime
[INFO] +- org.apache.commons:commons-lang3:jar:3.12.0:runtime
[INFO] \- commons-codec:commons-codec:jar:1.15:runtime
[INFO] ------------------------------------------------------------------------
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.6.0</version>
<executions>
<execution>
<id>copy</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.moditect</groupId>
<artifactId>moditect-maven-plugin</artifactId>
<version>1.0.0.Final</version>
<executions>
<execution>
<id>add-module-infos</id>
<phase>generate-resources</phase>
<goals>
<goal>add-module-info</goal>
</goals>
<configuration>
<outputDirectory>
${project.build.directory}/dependency
</outputDirectory>
<modules>
<module>
<artifact>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.13.0</version>
</artifact>
<moduleInfoSource>
module org.apache.commons.io {
exports org.apache.commons.io;
exports org.apache.commons.io.build;
exports org.apache.commons.io.charset;
exports org.apache.commons.io.comparator;
exports org.apache.commons.io.file;
exports org.apache.commons.io.file.attribute;
exports org.apache.commons.io.file.spi;
exports org.apache.commons.io.filefilter;
exports org.apache.commons.io.function;
exports org.apache.commons.io.input;
exports org.apache.commons.io.input.buffer;
exports org.apache.commons.io.monitor;
exports org.apache.commons.io.output;
exports org.apache.commons.io.serialization;
}
</moduleInfoSource>
</module>
</modules>
<overwriteExistingFiles>true</overwriteExistingFiles>
</configuration>
</execution>
</executions>
</plugin>
<moduleInfoSource>
content?External Libraries
. Double-click on the entry, right click on the .jar
, open in -> Explorer.jdeps -generate-module-info . {jar_file_name}.jar
module-info.java
file with a text editor and copy the content<moduleInfoSource>
section<modules>
, <launcher>
sections according to your project information.javafx.Application
directly. We can create a launcher class which looks like this (reference pending):launcher class
public class Launcher {
public static void main(String[] args) {
HelloApplication.main(args);
}
}
pom.xml
<execution>
<id>create-runtime-image</id>
<phase>package</phase>
<goals>
<goal>create-runtime-image</goal>
</goals>
<configuration>
<jarInclusionPolicy>APP_WITH_DEPENDENCIES</jarInclusionPolicy>
<modulePath>
<path>${project.build.directory}/${project.artifactId}-${project.version}.${project.packaging}</path>
<path>${project.build.directory}/dependency</path>
</modulePath>
<modules>
<module>com.example.soone</module>
</modules>
<launcher>
<name>hello</name>
<module>com.example.soone/com.example.soone.Launcher</module>
</launcher>
<outputDirectory>
${project.build.directory}/jlink-image
</outputDirectory>
</configuration>
</execution>