Gradle jlink 插件在 createMergedModule 期间失败 "the service implementation does not have a default constructor"

Gradle jlink plugin fails during createMergedModule with "the service implementation does not have a default constructor"

我正在使用 Gradle(4.10.3,但我已经尝试了 5.4.1 之前的大多数版本)以及 JDK 12.0.1 和 org.beryx.jlink 插件( 2.10.4),但每次我尝试创建 jlink 图像时 运行 都会遇到此错误:

-> Task :createMergedModule

Cannot derive uses clause from service loader invocation in: com/fasterxml/jackson/databind/ObjectMapper.run().

Cannot derive uses clause from service loader invocation in: com/fasterxml/jackson/databind/ObjectMapper.secureGetServiceLoader().

Cannot derive uses clause from service loader invocation in: org/apache/commons/compress/utils/ServiceLoaderIterator.().

C:\Users\MyName\IdeaProjects\myapp\build\jlinkbase\tmpjars\myapp.merged.module\module-info.java:393: error: the service implementation does not have a default constructor: XBeansXPath provides org.apache.xmlbeans.impl.store.PathDelegate.SelectPathInterface with org.apache.xmlbeans.impl.xpath.saxon.XBeansXPath;

C:\Users\MyName\IdeaProjects\myapp\build\jlinkbase\tmpjars\myapp.merged.module\module-info.java:394: error: the service implementation does not have a default constructor: XBeansXQuery provides org.apache.xmlbeans.impl.store.QueryDelegate.QueryInterface with org.apache.xmlbeans.impl.xquery.saxon.XBeansXQuery; 2 errors

-> Task :createMergedModule FAILED

当我点击合并 module-info.java 中抛出错误的行时,它指向以下两个:

provides org.apache.xmlbeans.impl.store.PathDelegate.SelectPathInterface with org.apache.xmlbeans.impl.xpath.saxon.XBeansXPath;
provides org.apache.xmlbeans.impl.store.QueryDelegate.QueryInterface with org.apache.xmlbeans.impl.xquery.saxon.XBeansXQuery;

我的 build.gradle 文件如下所示:

plugins {
    id 'application'
    id 'idea'
    id 'java'
    id 'org.openjfx.javafxplugin' version '0.0.7'
    id 'org.beryx.jlink' version '2.10.4'
}

repositories {
    mavenCentral()
}

dependencies {
    compile 'org.apache.commons:commons-csv:1.6'
    compile 'org.apache.poi:poi-ooxml:4.1.0'
    compile 'com.fasterxml.jackson.core:jackson-core:2.9.9'
    compile 'com.fasterxml.jackson.core:jackson-annotations:2.9.9'
    compile 'com.fasterxml.jackson.core:jackson-databind:2.9.9'
    testCompile 'org.junit.jupiter:junit-jupiter-api:5.5.0-M1'
    testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.5.0-M1'
}

// ### Application plugin settings
application {
    mainClassName = "$moduleName/path.to.myapp"
}

// ### Idea plugin settings
idea {
    module {
        outputDir = file("out/production/classes")
    }
}

// ### Java plugin settings
sourceCompatibility = JavaVersion.VERSION_11

compileJava {
    options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation"
}

test {
    useJUnitPlatform()
    testLogging {
        events 'PASSED', 'FAILED', 'SKIPPED'
    }
}

// ### JavaFX plugin settings
javafx {
    version = "12.0.1"
    modules = ['javafx.controls', 'javafx.fxml']
}

// ### jlink plugin settings
jlink {
    options = ['--strip-debug', '--compress', '2', '--no-header-files', '--no-man-pages']
    launcher {
        name = 'myapp'
    }
}

关于如何解决这个问题的任何想法?

以下可能的解决方案仅基于您的构建文件,不了解您的 module-info 或项目代码,因此它可能无法工作。

它也是基于 jlink 插件存储库中的 issue

首先,让我解释一下这个插件是如何工作的:由于 (JDK) jlink 工具不允许 non-modular 依赖项,插件将尝试收集所有依赖项并即时创建一个模块,可以将其添加到 module-path。此模块名为 $yourModuleName.mergedModule.

现在我将您的依赖项添加到一个简单的 JavaFX 项目中。当我 运行 ./gradlew jlink 时,我得到了与您发布的相同的错误。如果检查错误:

myapp\build\jlinkbase\tmpjars\myapp.merged.module\module-info.java:394: error

这表明创建的模块名为 myapp.merged.module,并且它有一个 module-info 描述符。如果你打开它,你会看到所有的 exports(该模块默认会导出每个依赖包)、requiresprovides:

open module myapp.merged.module {
    exports com.fasterxml.jackson.annotation;
    exports com.fasterxml.jackson.core;
    exports com.fasterxml.jackson.core.async;
    ...
    exports schemaorg_apache_xmlbeans.system.sXMLTOOLS;
    requires java.xml.crypto;
    requires java.logging;
    requires java.sql;
    requires java.xml;
    requires java.desktop;
    requires java.security.jgss;
    requires jdk.javadoc;
    uses java.nio.file.spi.FileSystemProvider;
    provides com.fasterxml.jackson.core.JsonFactory with com.fasterxml.jackson.core.JsonFactory;
    provides com.fasterxml.jackson.core.ObjectCodec with com.fasterxml.jackson.databind.ObjectMapper;
    provides org.apache.xmlbeans.impl.store.QueryDelegate.QueryInterface with org.apache.xmlbeans.impl.xquery.saxon.XBeansXQuery;
    provides org.apache.xmlbeans.impl.store.PathDelegate.SelectPathInterface with org.apache.xmlbeans.impl.xpath.saxon.XBeansXPath;
}

那么现在的问题是:你是否应该在你自己的模块中增加一些需求?答案解释here: that will increase unnecessary your project's size. A better way is to use the mergedModule脚本块:

The mergedModule block allows you to configure the module descriptor of the merged module

并且:

the module descriptor is created using the algorithm implemented by the suggestMergedModuleInfo task.

如果你 运行 ./gradlew suggestMergedModuleInfo 你基本上会得到与上面相同的合并模块描述符的内容。

一个可能的解决方案是开始只向合并的模块描述符添加一些要求,然后重试。

我开始于:

jlink {

    mergedModule {
        requires "java.xml"
    }

    options = ['--strip-debug', '--compress', '2', '--no-header-files', '--no-man-pages']
    launcher {
        name = 'myapp'
    }
}

我可以 运行 ./gradlew jlink 成功。

如果您现在检查合并的模块描述符,它将看起来像:

open module myapp.merged.module {
    requires java.xml;

    exports com.fasterxml.jackson.annotation;
    exports com.fasterxml.jackson.core;
    exports com.fasterxml.jackson.core.async;
    ...
    exports schemaorg_apache_xmlbeans.system.sXMLTOOLS;
}

仅包含显式 requires,所有导出,但不包含 provides,因此错误将消失。

因为我没有你的代码,所以我不能说这是否适合你,但它对我有相同的依赖关系。