将传递依赖转换为 compileOnly 依赖

问题描述

我正在尝试使用 Osgi 来允许我使用两个不同版本的传递依赖项。计划是一个版本(较新的版本)将隐藏在 Osgi 包中,另一个将像往常一样位于运行时类路径中。

我已经使用 Gradle(使用 Groovy DSL)构建了 bundle jar,但问题是它相关的运行时依赖是错误的——它带来了较新的版本,它应该隐藏在 bundle 中。当我这样做时,在 build.gradle 文件中仍然如此:

compileOnly deps.diffx
runtimeOnly(deps.diffx) {
    exclude group: 'com.propensive',module: 'magnolia_' + versions.scala_v
}

如果我使用 Gradle dependencies 任务检查依赖项,它显示 magnolia 已按预期从 runtimeOnly 配置中排除 - 但从 { {1}} 配置。

如果我然后使用 runtimeClasspath 尝试找出此依赖项的来源,它会告诉我较新的版本来自 ./gradlew dependencyInsight --dependency magnolia_2.12 --configuration runtime,具体取决于 runtimeClasspath,这是通过冲突解决选择。嗯,谢谢 - 我已经知道了。问题是,为什么我的排除没有应用于派生配置?

基本上我想做与this question相反的事情。

我也尝试过约束版本,但它们表现出同样的问题:

diffx

解决方法

来自the Gradle documentation

从好的方面来说,与 Maven 相比,Gradle 的排除处理考虑了整个依赖关系图。因此,如果一个库有多个依赖项,则仅当所有依赖项都同意时才会执行排除。例如,如果我们将 opencsv 作为另一个依赖添加到我们上面的项目中,它也依赖于 commons-beanutils,则不再排除 commons-collection,因为 opencsv 本身不排除它。

因此,我们可以使用 dependency resolve rule:

compileOnly deps.diffx
runtimeOnly(deps.diffx) {
    constraints {
        implementation('com.propensive:magnolia_' + versions.scala_v + ':0.10.0') {
            because 'this version is required by our other dependencies'
        }
    }
}

然后将依赖项改回简单的单个 def magnoliaVersion = '0.10.0' configurations.runtimeClasspath { resolutionStrategy.eachDependency { DependencyResolveDetails details -> if (details.requested.group == 'com.propensive' && details.requested.name.startsWith("magnolia_") && details.requested.version != magnoliaVersion) { details.useVersion magnoliaVersion details.because 'this version is required by our other dependencies' } } } 依赖项:

implementation

不幸的是,如文档所述,此解析规则未发布,因此必须在任何依赖的 Gradle 模块中再次应用。