I created two Maven projects 'javafx' and 'commonfx' to reproduce an error. Two Maven JavaFX Projects

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;
}

这两个项目都有一个资源文件夹.他们不会输出这些文件夹,但无论如何,我不断收到错误消息:

Error occurred during initialization of boot layer

java.lang.LayerInstantiationException: 
Package bundle in both module javafx and module commonfx

每当我重新启动应用程序时,我都会收到新的错误消息.但每次资源文件夹在两个模块中的名称相同.

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.

使用的技术:

  • Java 21
  • RDX SDK 21
  • 适用于企业Java和Web开发人员的日食IDE版本:2024-03
  • Maven 3.9.6

maven资源文件夹是否可能被忽视?

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:这是一个拆分包问题.解决方案是:

  1. 验证您的包裹,使其独一无二.

  2. 将您的包初始化为不是有效包名称的名称(如果包不包含类文件,则仅为选项).

  3. 使您的代码是非模块化的,并将您的代码及其依赖项(MEK除外)放置在类路径上.

请参阅jewelsea's answer,了解第一个解决方案的工作示例,以及为什么第三个解决方案可能最适合您(提问者)的特定场景的原因.


The Problem

您看到的错误是由于包含相同包的两个模块造成的.这不是通过Maven排除资源文件夹来解决的问题.

仅限资源的包

首先,包不需要包含被视为包的类文件.真正重要的是包有一个有效的名称并包含something个,无论是类文件还是其他资源.另外,类文件基本上只是一种特殊类型的资源.从(典型)类加载器的Angular 来看,资源和类文件的查找和打开方式完全相同.

换句话说,bundleconfigimages都是您的包.这些都是有效的包名称并且包含资源.此外,由于这些是模块中包含的包,因此其中的资源为encapsulated(基于包的功能).

拆分包装

当两个(或更多)模块包含同名的包时,该包被称为"分裂".Java Platform Module System确保当存在拆分包时,两个(或更多)模块不会相互干扰.它在加载模块过程中的两个不同步骤中确保了这一点.

module resolution期间,如果出现以下情况,分辨率可能会失败:

配置中的两个或多个模块将相同的包输出到读取两者的模块.这包括包含包p的模块M读取将p输出到M的另一模块的情况.

那么module layer就是defined,如果出现以下情况,它可能会失败:

具有相同包的两个或更多模块映射到相同的类加载器.

bundleimages都没有被输出,因此您的两个模块正在得到很好的解决.您看到的错误在定义层时发生,因此异常类型为LayerInstantiationException.Your two modules are being mapped to the same class loader (the system/application class loader).

基本上,对于通过--module-path命令行选项加载的模块,完全禁止拆分包.模块可读性图和是否输出拆分包都无关紧要.

也见Java 9 overlapping non-exported packages.


Solutions

至少有三种解决方案:使用唯一的包名称、使用无效的包名称或使代码非模块化.

唯一的程序包名称

即使不出口包,您也应该使用唯一的包名称.产生唯一包名称的传统方法是将反向域名与标识产品的名称结合起来.这两个东西通常是从所述文物的Maven坐标中提取的.例如,如果您有:

<groupId>com.example</groupId>
<artifactId>commonsfx</artifactId>

在您的TOM中,那么您的包名称将是com.example.commonsfx.这也是您模块的一个好名字.

完整示例请参阅jewelsea's answer.

使用无效的包名称

如果您将bundleimages重命名为不是有效的包名称,那么它们将不再被视为包.这将使您在多个模块中拥有相同的"包",但这也意味着这些"包"中的资源不再被封装.

Warning:仅在包不包含类文件时才是一个选项.

使您的代码非模块化

如果您使代码为非模块化并将其置于类路径上,那么您的拆分包将不再是问题.对于您的特定情况,这可能是最好的解决方案.看看jewelsea's answer结尾的原因.

Java相关问答推荐

使用json参数通过单击jSP文件中的按钮来运行server时出现问题

如何在Spring Boot中创建500错误的响应正文?

具有默认分支的JUnit代码覆盖率切换声明

Annotation @ Memphier无法正常工作,并表示:class需要一个bean,但找到了2个bean:

Java:根据4象限中添加的行数均匀分布行的公式

SQlite for Android无法使用json_group_array/json_object

有没有一种方法使保持活动设置专用于java.net.http.HttpClient的一个实例

是否保证在事务性块的末尾标记违反约束?

确定Java中Math.Ranb()输出的上限

Java中如何根据Font.canDisplay方法对字符串进行分段

在bash中将数组作为Java程序的参数传递

将关键字与正文中的_Allowed匹配,但带有__Signing可选后缀

为什么在maven中,getLast方法不适用于List?

如何让JVM在SIGSEGV崩溃后快速退出?

Spring安全令牌刷新和JWT签名与本地计算的签名不匹配

EXCEL中的公式单元格显示#NAME?

如果List是一个抽象接口,那么Collectors.toList()如何处理流呢?

使用原子整数的共享计数器并发增量

人们在 IntelliJ 上将-Dhttp.proxyHost=your.proxy.net -Dhttp.proxyPort=8080放在哪里?

JAVA 正则表达式识别字符串string或字符串内的字符char