Java 如何解决Gradle中的传递依赖冲突

Java 如何解决Gradle中的传递依赖冲突,java,gradle,gradle-plugin,Java,Gradle,Gradle Plugin,我在Gradle构建中遇到了我的第一个可传递依赖冲突,并且不确定许多文档化的方法中哪一个最适合我的案例 我有一个根项目,负责在多个子Gradle插件项目上运行功能测试,但除了测试用例之外没有其他代码。我正在使用该方法获取测试类路径中的子项目 // Write the plugin's classpath to a file to share with the tests task pluginUnderTestMetadata { def outputDir = file("${buil

我在Gradle构建中遇到了我的第一个可传递依赖冲突,并且不确定许多文档化的方法中哪一个最适合我的案例

我有一个根项目,负责在多个子Gradle插件项目上运行功能测试,但除了测试用例之外没有其他代码。我正在使用该方法获取测试类路径中的子项目

// Write the plugin's classpath to a file to share with the tests
task pluginUnderTestMetadata {
    def outputDir = file("${buildDir}/pluginUnderTestMetadata")
    def runtimeClasspath = sourceSets.main.runtimeClasspath

    outputs.dir(outputDir)
        .withPropertyName("outputDir")

        inputs.files(runtimeClasspath)
                .withPropertyName("runtimeClasspath")
                .withNormalizer(ClasspathNormalizer)


    doLast {
        outputDir.mkdirs()
        file("$outputDir/plugin-classpath.txt").text = runtimeClasspath.join("\n")
    }
}

dependencies {
    implementation localGroovy(),
            gradleApi(),
            project(':waweb.site.plugin'),
            project(':waweb.site.plugin.js'),
            project(':waweb.site.plugin.sass'),
            project(':waweb.site.plugin.template'),
            project(':waweb.site.plugin.war')

    testRuntimeOnly files(pluginUnderTestMetadata)
    testImplementation gradleTestKit(),
            "junit:junit:${JUNIT_VER}",
            "org.assertj:assertj-core:${ASSERTJ_VER}",
            "org.hamcrest:hamcrest:${HAMCREST_VER}",
            "net.serenity-bdd:serenity-core:${SERENITY_VER}",
            "net.serenity-bdd:serenity-junit:${SERENITY_VER}",
            "net.serenity-bdd:serenity-cucumber:${SERENITY_CUCUMBER_VER}"
}
这一切都非常有效,直到我将
closure compiler
作为一个子项目的依赖项添加到其中一个子项目,这会导致运行时错误:

1) Error injecting constructor, java.lang.NoSuchMethodError: com.google.gson.Gson.<init>(Lcom/google/gson/internal/Excluder;Lcom/google/gson/FieldNamingStrategy;Ljava/util/Map;ZZZZZZZLcom/google/gson/LongSerializationPolicy;Ljava/lang/String;IILjava/util/List;Ljava/util/List;Ljava/util/List;)V
at net.thucydides.core.reports.json.gson.GsonJSONConverter.<init>(GsonJSONConverter.java:38)
while locating net.thucydides.core.reports.json.gson.GsonJSONConverter
at net.thucydides.core.guice.ThucydidesModule.configure(ThucydidesModule.java:56)
while locating net.thucydides.core.reports.json.JSONConverter
at net.serenitybdd.core.history.FileSystemTestOutcomeSummaryRecorder.<init>(FileSystemTestOutcomeSummaryRecorder.java:42)
while locating net.serenitybdd.core.history.FileSystemTestOutcomeSummaryRecorder
at net.thucydides.core.guice.ThucydidesModule.configure(ThucydidesModule.java:72)
while locating net.serenitybdd.core.history.TestOutcomeSummaryRecorder
    for the 2nd parameter of net.serenitybdd.core.history.HistoricalFlagProvider.<init>(HistoricalFlagProvider.java:28)
while locating net.serenitybdd.core.history.HistoricalFlagProvider
at net.thucydides.core.guice.ThucydidesModule.configure(ThucydidesModule.java:71)
while locating net.thucydides.core.model.flags.FlagProvider
我相信这是由于如下依赖性报告中所示的gson版本冲突造成的。如果我能以某种方式分离这些类路径,这样它们就可以毫无问题地使用它们的内部可传递依赖项,那将是一个理想的选择,但鉴于我的不寻常的设置,我不确定如何进行,或者这是否可能。我需要定义一些约束、使用一个平台、解耦构建还是完全其他什么

我们将非常感谢您在工作解决方案之外提供的任何见解

简略的依赖关系报告


我真的应该等24小时再发帖,因为当我想到其他事情时,答案总是随机出现在我的脑海中

解决方案:

configurations {
    pluginsUnderTest
}

task pluginUnderTestMetadata {
    def outputDir = file("${buildDir}/pluginUnderTestMetadata")
    def runtimeClasspath = configurations.pluginsUnderTest

    outputs.dir(outputDir)
        .withPropertyName("outputDir")

    inputs.files(runtimeClasspath)
            .withPropertyName("runtimeClasspath")
            .withNormalizer(ClasspathNormalizer)


    doLast {
        outputDir.mkdirs()
        file("$outputDir/plugin-classpath.txt").text = runtimeClasspath.join("\n")
    }
}

dependencies {
    pluginsUnderTest localGroovy(),
            gradleApi(),
            project(':waweb.site.plugin'),
            project(':waweb.site.plugin.js'),
            project(':waweb.site.plugin.sass'),
            project(':waweb.site.plugin.template'),
            project(':waweb.site.plugin.war')

    testRuntimeOnly files(pluginUnderTestMetadata)
    testImplementation gradleTestKit(),
            "junit:junit:${JUNIT_VER}",
            "org.assertj:assertj-core:${ASSERTJ_VER}",
            "org.hamcrest:hamcrest:${HAMCREST_VER}",
            "net.serenity-bdd:serenity-core:${SERENITY_VER}",
            "net.serenity-bdd:serenity-junit:${SERENITY_VER}",
            "net.serenity-bdd:serenity-cucumber:${SERENITY_CUCUMBER_VER}"
}

如果任何人希望在插件项目的各种配置上设置功能测试,希望这至少能为他们节省一些时间。

注意:我只有在实现类路径上的项目,所以我可以在pluginUnderTestMetadata中获取它们,因此,理想的解决方案可能是以某种方式生成此文本文件,而不显式地将项目添加为依赖项。plugin-classpath.txt是正确的,但是当这些项目被列为直接依赖项时,测试运行程序无法初始化。
configurations {
    pluginsUnderTest
}

task pluginUnderTestMetadata {
    def outputDir = file("${buildDir}/pluginUnderTestMetadata")
    def runtimeClasspath = configurations.pluginsUnderTest

    outputs.dir(outputDir)
        .withPropertyName("outputDir")

    inputs.files(runtimeClasspath)
            .withPropertyName("runtimeClasspath")
            .withNormalizer(ClasspathNormalizer)


    doLast {
        outputDir.mkdirs()
        file("$outputDir/plugin-classpath.txt").text = runtimeClasspath.join("\n")
    }
}

dependencies {
    pluginsUnderTest localGroovy(),
            gradleApi(),
            project(':waweb.site.plugin'),
            project(':waweb.site.plugin.js'),
            project(':waweb.site.plugin.sass'),
            project(':waweb.site.plugin.template'),
            project(':waweb.site.plugin.war')

    testRuntimeOnly files(pluginUnderTestMetadata)
    testImplementation gradleTestKit(),
            "junit:junit:${JUNIT_VER}",
            "org.assertj:assertj-core:${ASSERTJ_VER}",
            "org.hamcrest:hamcrest:${HAMCREST_VER}",
            "net.serenity-bdd:serenity-core:${SERENITY_VER}",
            "net.serenity-bdd:serenity-junit:${SERENITY_VER}",
            "net.serenity-bdd:serenity-cucumber:${SERENITY_CUCUMBER_VER}"
}