I created two Maven projects 'javafx' and 'commonfx' to reproduce an error.
module commonfx {
exports commonfx.calculator;
}
module javafx {
requires javafx.controls;
requires javafx.graphics;
requires javafx.fxml;
requires commonfx;
opens org.example to javafx.graphics, javafx.fxml;
}
Both projects have an resource folder. They do not export those folders but anyway I am getting constantly error messages:
Error occurred during initialization of boot layer
java.lang.LayerInstantiationException:
Package bundle in both module javafx and module commonfx
Whenever I rerun the application, I am getting a new error message. But each time a resource folder is same named in both modules.
Error occurred during initialization of boot layer
java.lang.LayerInstantiationException:
Package images in both module commonfx and module javafx
Error occurred during initialization of boot layer
java.lang.LayerInstantiationException:
Package main.resources.images in both module commonfx and module javafx.
Used technologies:
Is it possible that the maven resource folder are getting ignored?
Code to reproduce the exception:
Project commonfx
package commonfx.calculator;
public class FxCalculator {
public FxCalculator() {
super();
}
public Integer calculate() {
return 2;
}
}
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>common.fx</groupId>
<artifactId>commonfx</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<javafx.version>21</javafx.version>
<javafx.maven.plugin.version>0.0.8</javafx.maven.plugin.version>
</properties>
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>21.0.2</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>${javafx.version}</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-web</artifactId>
<version>${javafx.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>${javafx.maven.plugin.version}</version>
</plugin>
</plugins>
</build>
</project>
Project javafx
package org.example;
import commonfx.calculator.FxCalculator;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class Javafx extends Application {
private FxCalculator calculator;
@Override
public void start(Stage stage) {
String javaVersion = System.getProperty("java.version");
String javafxVersion = System.getProperty("javafx.version");
calculator = new FxCalculator();
Label l = new Label("Hello, JavaFX " + javafxVersion + ", running on Java " + javaVersion + "." + " Number FX: " + calculator.calculate());
Scene scene = new Scene(new StackPane(l), 640, 480);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
}
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>javafx</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<javafx.version>21</javafx.version>
<javafx.maven.plugin.version>0.0.8</javafx.maven.plugin.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>3.2.4</version>
</dependency>
<dependency>
<groupId>net.rgielen</groupId>
<artifactId>javafx-weaver-spring-boot-starter</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>21.0.2</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>${javafx.version}</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-web</artifactId>
<version>${javafx.version}</version>
</dependency>
<dependency>
<groupId>common.fx</groupId>
<artifactId>commonfx</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>${javafx.maven.plugin.version}</version>
<configuration>
<mainClass>org.example.Javafx</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
TL;DR: This is a split package problem. The solution is to either:
Rename your packages so that they are unique.
Rename your packages to something that is not a valid package name (only an option if the packages do not contain class files).
Make your code non-modular and place your code and its dependencies (except JavaFX) on the class-path.
See jewelsea's answer for a working example of the first solution, as well as reasons why the third solution is likely the best for your (the questioner's) specific scenario.
The error you are seeing is due to two modules containing the same package. This is not something that should be solved by excluding resource folders via Maven.
First, it is not a requirement for a package to contain class files to be considered a package. Really the only important thing is that the package has a valid name and contains something, whether that be a class file or some other resource. Plus, class files are basically just a special type of resource. From the perspective of a (typical) class loader, resources and class files are found and opened in the exact same way.
In other words, bundle
, config
, and images
are all packages in your case. Those are valid package names and they contain resources. Also, since those are packages contained in the module, the resources within them are encapsulated (a feature based on packages).
When two (or more) modules contain a package with the same name, that package is said to be "split". The Java Platform Module System ensures that when a split package exists, the two (or more) modules do not interfere with each other. It ensures this at two different steps in the process of loading modules.
During module resolution, the resolution can fail if:
Two or more modules in the configuration export the same package to a module that reads both. This includes the case where a module
M
containing packagep
reads another module that exportsp
toM
.
Then a module layer is defined, which can fail if:
Two or more modules with the same package are mapped to the same class loader.
Neither bundle
nor images
is exported, so your two modules are being resolved just fine. The error you see occurs when the layer is being defined, hence LayerInstantiationException
as the exception type. Your two modules are being mapped to the same class loader (the system/application class loader).
Basically, split packages are completely forbidden for modules loaded via the --module-path
command line option. Both the module readability graph and whether or not a split package is exported are irrelevant.
Also see Java 9 overlapping non-exported packages.
There are at least three solutions: use unique package names, use invalid package names, or make your code non-modular.
You should use unique package names, even when the package is not going to be exported. A conventional way to come up with a unique package name is by combining a reversed domain name with a name that identifies the artifact. These two things are typically pulled from the Maven coordinates of said artifact. For example, if you have:
<groupId>com.example</groupId>
<artifactId>commonsfx</artifactId>
In your POM, then your package name would be com.example.commonsfx
. That would also be a good name for your module.
See jewelsea's answer for a full example.
If you rename bundle
and images
to something that is not a valid package name, then they will no longer be considered packages. This will let you have the same "package" in multiple modules, but it will also mean the resources within those "packages" are no longer encapsulated.
Warning: This is only an option if the packages do not contain class files.
If you make your code non-modular and place it on the class-path then your split packages will no longer be a problem. For your specific case, this is likely the best solution. See the end of jewelsea's answer for reasons why.