使用Moditect为现有的Maven依赖项添加module-info。

6
我正在使用JavaFX,并且有一些依赖项不是自动模块。当尝试运行mvn clean javafx:jlink时,我收到以下错误提示:
Error: automatic module cannot be used with jlink: org.apache.commons.io from [...]`

这也对org.apache.commons.commons-lang3commons-codec.commons-codec出现了错误。我看到的错误是随机的。
所以我研究了使用jdeps来为依赖项生成模块信息,例如。
jdeps --generate-module-info tmp .../.m2/repository/commons-io/commons-io/2.12.0/commons-io-2.12.0.jar

然后我使用Moditect将module-info添加到现有的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>

但是我仍然遇到相同的错误。
我的模块信息:
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;
}

我的完整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>

我还运行了mvn dependency:tree来生成以下内容:
[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] ------------------------------------------------------------------------

1
首先,为什么要使用插件作为依赖?其次,为什么将模块的输出定义为modules,因为通常的modul-info.class必须位于jar/root-location中...? - undefined
还从依赖项中移除了其他插件,并更新了我的问题。 - Conor Egan
你能展示一下jlink的配置吗?它是否使用${project.build.directory}/modules - undefined
@dan1st 你可以提供的选项可以在这里找到:https://github.com/openjfx/javafx-maven-plugin#javafxjlink-options。我有maven配置,但没有可选的选项。我不确定你的意思是什么? - undefined
我也按照这个链接进行了操作:https://openjfx.io/openjfx-docs/#maven。运行时镜像 > 使用 Maven 进行模块化。 - undefined
显示剩余4条评论
1个回答

1
问题
- JLink无法与自动模块(即没有module-info.java文件的包)一起使用。
步骤
- 使用maven-dependency-plugin将依赖项复制到{build_folder}/dependency。
<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>

使用moditect-maven-plugin为自动模块添加module-info。
<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>内容?
  • 进入包含所需(依赖).jar文件的文件夹
  • 如果您使用Intellij IDEA,在项目视图中,有一个名为External Libraries的部分。双击条目,在.jar上右键单击,选择打开方式 ->资源管理器。
  • 在该文件夹中打开命令提示符
  • jdeps -generate-module-info . {jar_file_name}.jar
  • 确保PATH环境变量设置正确
  • 用文本编辑器打开生成的module-info.java文件并复制内容
  • 粘贴到<moduleInfoSource>部分

创建运行时镜像(使用jlink,在后端)

  • 请根据您的项目信息更改<modules><launcher>部分。
  • 如果您的模块是非模块化的,重要的是主类不直接扩展javafx.Application。我们可以创建一个看起来像这样的启动器类(参考待定):

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>
链接到演示存储库

建议

  • 我建议将构建系统更改为Gradle,它与自动模块更好地配合,您不必手动解决依赖关系,尤其是在使用JavaFX时,这将节省很多时间。

谢谢您的回复。如果您正在使用module-info.java,那么您就不需要一个不继承Application的主类。您提供的最后一个执行步骤应该放在哪里?为什么切换到Gradle会让使用自动模块更容易? - undefined
1
在执行moditect插件时,请参考项目链接中的pom.xml。在Gradle中,它支持自动模块。您不必使用jdeps来找出module-info.java,这在某些情况下效果不佳,并且在较大的第三方依赖项(如Spring框架的某些库)中需要更多的工作。 - undefined
谢谢提供的信息,我想尝试使用Maven来使其工作,但如果失败的话,我会尝试迁移到Gradle。提供的项目链接无效,请您能否编辑您的回答? - undefined
1
抱歉回复晚了,我已经更新了链接。 - undefined
1
所谓的“模块化的jar”意味着它已经被模块化,并且具有module-info.java,不需要在Moditect中进行额外的设置。但是据我所记,使用jackson-databind可能会遇到一些多版本的问题,这是另一个话题了。很高兴你在Gradle上没有遇到问题 :) - undefined
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接