From what I understand and read already the problem is that the module is imported twice somewhere, but I don't understand where. This is my module-info.java file:
module main {
requires org.apache.logging.log4j;
requires javafx.controls;
requires javafx.fxml;
requires java.sql;
}
And this is my build.gradle
plugins {
id 'java'
id 'application'
id 'org.javamodularity.moduleplugin' version '1.8.12'
id 'org.openjfx.javafxplugin' version '0.0.13'
id 'org.beryx.jlink' version '2.25.0'
}
group 'org'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
ext {
junitVersion = '5.10.0'
}
sourceCompatibility = '21'
targetCompatibility = '21'
tasks.withType(JavaCompile).configureEach {
options.encoding = 'UTF-8'
}
application {
mainModule = 'main'
mainClass = 'main.HelloApplication'
}
javafx {
version = '21'
modules = ['javafx.controls', 'javafx.fxml']
}
dependencies {
implementation('org.controlsfx:controlsfx:11.1.2')
implementation('com.dlsc.formsfx:formsfx-core:11.6.0') {
exclude(group: 'org.openjfx')
}
implementation('net.synedra:validatorfx:0.4.0') {
exclude(group: 'org.openjfx')
}
implementation('org.kordamp.bootstrapfx:bootstrapfx-core:0.4.0')
// https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core
implementation 'org.apache.logging.log4j:log4j-core:2.22.1'
// https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-api
implementation 'org.apache.logging.log4j:log4j-api:2.22.0'
testImplementation platform('org.junit:junit-bom:5.9.1')
testImplementation 'org.junit.jupiter:junit-jupiter'
// https://mvnrepository.com/artifact/com.mysql/mysql-connector-j
runtimeOnly 'com.mysql:mysql-connector-j:8.3.0'
}
test {
useJUnitPlatform()
}
jar {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
manifest {
attributes('Main-Class': 'main.HelloApplication', 'Multi-Release': 'true')
}
from {
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
}
jlink {
imageZip = project.file("${buildDir}/distributions/app-${javafx.platform.classifier}.zip")
options = ['--strip-debug', '--compress', '2', '--no-header-files', '--no-man-pages']
launcher {
name = 'app'
}
}
jlinkZip {
group = 'distribution'
}
I tried changing my module-info file a bunch and if this error is solved then I have a different one each time for example:
module main {
requires org.apache.logging.log4j;
requires javafx.controls;
requires javafx.fxml;
requires java.sql;
requires org.controlsfx.controls;
requires com.dlsc.formsfx;
requires org.kordamp.bootstrapfx.core;
exports main;
exports main.model;
exports main.repository;
exports main.service;
exports main.controller;
opens main;
opens main.model;
opens main.repository;
opens main.service;
opens main.controller;
}
This will now generate "Module main contains package javafx.beans.value, module javafx.base exports package javafx.beans.value to main" or in another run "Module main contains package javafx.event, module javafx.base exports package javafx.event to main".
TL;DR: Do not create a fat JAR file when developing modular applications.
That error means that two modules contain the same package. The Java Platform Module System (JPMS) does not allow split packages. And in this case, the error is saying that your own module contains packages from a JavaFX module.
You have configured the jar
task to create a so-called fat JAR file (i.e., a JAR with dependencies). Those dependencies include the JavaFX modules. But this will cause issues with the run
task at the least. When your code is modular, the run
task depends on the jar
task and executes the JAR file as a module1. The run
task will also place dependencies on the module-path2. Those dependencies include the JavaFX modules3. Thus, you now have JavaFX packages split between your module and the JavaFX modules and you see your error.
I suspect the same problem will occur when executing the jlink
task, and probably all tasks that deal with JPMS modules, but I am not as familiar with The Badass JLink Plugin.
The solution is to remove the following from the jar
task configuration:
from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
As an aside, if you prefer to deploy your application as a fat JAR file instead of as a self-contained application, then I recommend you make your project non-modular. You should also exclude any and all module-info.class
files from the fat JAR file. And critically, your main class must not be a subclass of Application
. You must create a separate "launcher" main class that, at a minimum, simply launches the JavaFX application.
For more information about packaging JavaFX applications, see the "Packaging" section of the JavaFX tag info page.
1. When your code is non-modular then the run
task only depends on the compileJava
and processResources
tasks (indirectly via the classes
task). The difference in behavior between modular and non-modular projects was part of a solution to a problem regarding resources and modules.
2. The org.openjfx.javafxplugin
plugin will modify the run
task to place JavaFX on the module-path for non-modular projects. In other words, JavaFX will end up on the module-path regardless.
3. The dependencies include not only JavaFX but also all the other non-test dependencies you declared. You are getting an error specifically relating to JavaFX packages, but the problem exists for all dependencies.