将您的构建从 Gradle 8.x 升级到最新版本
本章提供将您的 Gradle 8.x 构建迁移到最新 Gradle 版本所需的信息。要从 Gradle 4.x、5.x、6.x 或 7.x 迁移,请首先参阅较旧的迁移指南。
我们建议所有用户执行以下步骤
-
尝试运行
gradle help --scan
并查看生成的构建扫描的弃用视图。这使您可以查看适用于您构建的任何弃用警告。
或者,您可以运行
gradle help --warning-mode=all
以在控制台中查看弃用,但这可能不会报告那么多详细信息。 -
更新您的插件。
某些插件会因 Gradle 的新版本而崩溃,因为它们使用了已删除或更改的内部 API。上一步将通过在插件尝试使用已弃用的 API 部分时发出弃用警告,帮助您识别潜在问题。
-
运行
gradle wrapper --gradle-version 8.13
以将项目更新到 8.13。 -
尝试运行项目并使用问题排查指南调试任何错误。
从 8.12 及更早版本升级
潜在的破坏性变更
JvmTestSuite 的变更
testType
属性已从JvmTestSuite 中删除,并且 TestSuiteTargetName
和 TestSuiteType
属性均已删除。现在可以通过在要聚合的目标项目中指定测试套件的名称,在项目之间聚合测试报告和 JaCoCo 报告。
请参阅下文了解更多详细信息。
测试报告聚合和 Jacoco 聚合的变更
对孵化中的测试报告聚合和JaCoCo 报告聚合插件进行了一些更改。
插件现在为每个测试套件创建一个单一的测试结果变体,其中包含整个套件的所有测试结果,而不是每个测试目标一个变体。此更改允许聚合插件聚合具有多个目标的测试套件,而以前这会导致歧义的变体选择错误。
将来,随着我们继续开发这些插件,我们计划再次为每个测试套件目标创建一个结果变体,从而允许显式聚合来自某些目标的测试结果。
JacocoCoverageReport 和 AggregateTestReport 上的 testType
属性已被删除,并替换为新的 testSuiteName
属性
之前
reporting {
reports {
val testCodeCoverageReport by creating(JacocoCoverageReport::class) {
testType = TestSuiteType.UNIT_TEST
}
}
}
现在
reporting {
reports {
val testCodeCoverageReport by creating(JacocoCoverageReport::class) {
testSuiteName = "test"
}
}
}
调用 BuildLauncher.addJvmArguments
时的行为已更改
修复了问题(#31426),该问题导致 BuildLauncher.addJvmArguments
覆盖来自 org.gradle.jvmargs
系统属性的标志。升级到 Gradle 8.13 时,请确保您没有依赖此行为。如果需要覆盖系统属性,则应改用 BuildLauncher.setJvmArguments
。
val buildLauncher: BuildLauncher = connector.connect().newBuild()
buildLauncher.setJvmArguments("-Xmx2048m", "-Dmy.custom.property=value")
升级到 ASM 9.7.1
ASM 从 9.6 升级到 9.7.1,以确保更早地兼容 Java 24。
Project.task 方法的源代码级别弃用
Project
接口上的 Eager 任务创建方法已标记为 @Deprecated
,并且在构建脚本或插件代码中使用时将生成编译器和 IDE 警告。尚未使用 Gradle 弃用警告来指示其使用。
但是,如果构建配置为在 Kotlin 脚本或插件代码编译期间警告失败,则此更改可能会导致构建失败。
当这些方法在未来版本中完全弃用时,将在使用时打印标准的 Gradle 弃用警告。
弃用
在延迟提供器中递归查询 AttributeContainer
在 Gradle 9.0 中,从同一容器的属性值提供器内部查询 AttributeContainer
的内容将成为错误。
以下示例展示了禁止的行为
AttributeContainer container = getAttributeContainer();
Attribute<String> firstAttribute = Attribute.of("first", String.class);
Attribute<String> secondAttribute = Attribute.of("second", String.class);
container.attributeProvider(firstAttribute, project.getProviders().provider(() -> {
// Querying the contents of the container within an attribute value provider
// will become an error.
container.getAttribute(secondAttribute);
return "first";
}));
已弃用的 org.gradle.api.artifacts.transform.VariantTransformConfigurationException
此异常没有好的公共用例,并且不打算由用户抛出。在 Gradle 9.0 中,它将被 org.gradle.api.internal.artifacts.transform.VariantTransformConfigurationException
取代,仅供内部使用。
孵化中 UpdateDaemonJvm
中已弃用的属性
UpdateDaemonJvm
的以下属性现已弃用
-
jvmVersion
-
jvmVendor
它们分别被 languageVersion
和 vendor
取代。这允许 Java 工具链规范的配置和 UpdateDaemonJvm
任务可互换。
请注意,由于 vendor 属性的类型更改,使用 jvmVendor
属性执行 updateDaemonJvm
将导致任务失败。有关新的配置选项,请参阅文档。
使用 is
前缀和 Boolean
类型声明布尔属性
Gradle 属性名称是通过遵循 Java Bean 规范(有一个例外)派生的。Gradle 将具有 Boolean
返回类型和 is
前缀的方法识别为布尔属性。这是最初从 Groovy 继承的行为。Groovy 4 更密切地遵循 Java Bean 规范,并且 不再支持此例外。
当 Gradle 检测到布尔属性是从具有 Boolean
返回类型和 is
前缀的方法派生时,它将发出弃用警告。在 Gradle 9.0 中,这些方法将不再被视为定义 Gradle 属性。这可能会导致任务被认为是最新的,即使 Boolean
属性似乎是输入。
有两种选项可以解决此问题
-
引入一个新的方法,该方法以
get
而不是is
开头,并且具有相同的行为。旧方法不需要删除(为了保持二进制兼容性),但可能需要进行如下所示的调整。-
建议弃用
is-
方法,然后在未来的主要版本中将其删除。
-
-
将属性的类型(get 和 set)更改为
boolean
。这是一个破坏性更改。
对于使用第一个选项的任务输入属性,您还应该使用 @Deprecated
和 @ReplacedBy
注释旧的 is-
方法,以确保 Gradle 不会使用它。例如,以下代码
class MyValue {
private Boolean property = Boolean.TRUE;
@Input
Boolean isProperty() { return property; }
}
应替换为以下代码
class MyValue {
private Boolean property = Boolean.TRUE;
@Deprecated
@ReplacedBy("getProperty")
Boolean isProperty() { return property; }
@Input
Boolean getProperty() { return property; }
}
从 8.11 及更早版本升级
潜在的破坏性变更
升级到 Kotlin 2.0.21
嵌入式 Kotlin 已从 2.0.20 更新到 Kotlin 2.0.21。
升级到 Ant 1.10.15
Ant 已更新到 Ant 1.10.15。
升级到 Zinc 1.10.4
Zinc 已更新到 1.10.4。
Swift SDK 发现
为了确定 Swift 的 Mac OS X SDK 的位置,Gradle 现在将 --sdk macosx
参数传递给 xcrun
。这是必要的,因为如果没有此参数,SDK 在不同环境中可能会以不一致的方式被发现。
TaskContainer.create 方法的源代码级别弃用
TaskContainer
接口上的 Eager 任务创建方法已标记为 @Deprecated
,并且在构建脚本或插件代码中使用时将生成编译器和 IDE 警告。尚未使用 Gradle 弃用警告来指示其使用。
但是,如果构建配置为在 Kotlin 脚本或插件代码编译期间警告失败,则此行为可能会导致构建失败。
当这些方法在未来版本中完全弃用时,将在使用时打印标准的 Gradle 弃用警告。
弃用
已弃用的歧义转换链
以前,当至少有两个等长的工件转换链可用,并且它们将生成可以满足解析请求的兼容变体时,Gradle 将任意且静默地选择一个。
现在,Gradle 发出弃用警告,解释了这种情况
There are multiple distinct artifact transformation chains of the same length that would satisfy this request. This behavior has been deprecated. This will fail with an error in Gradle 9.0.
Found multiple transformation chains that produce a variant of 'root project :' with requested attributes:
- color 'red'
- texture 'smooth'
Found the following transformation chains:
- From configuration ':squareBlueSmoothElements':
- With source attributes:
- artifactType 'txt'
- color 'blue'
- shape 'square'
- texture 'smooth'
- Candidate transformation chains:
- Transformation chain: 'ColorTransform':
- 'BrokenColorTransform':
- Converts from attributes:
- color 'blue'
- texture 'smooth'
- To attributes:
- color 'red'
- Transformation chain: 'ColorTransform2':
- 'BrokenColorTransform2':
- Converts from attributes:
- color 'blue'
- texture 'smooth'
- To attributes:
- color 'red'
Remove one or more registered transforms, or add additional attributes to them to ensure only a single valid transformation chain exists.
在这种情况下,Gradle 无法知道应该使用两个(或更多)可能的转换链中的哪一个。选择任意链可能会导致性能低下,或者在修改构建的看似无关的部分时导致意外的行为更改。这可能是一个非常复杂的情况,并且该消息现在通过打印所有已注册的转换(按顺序排列)以及每个候选链的源(输入)变体来完整地解释这种情况。
当遇到此类故障时,构建作者应执行以下操作之一
-
在注册链中存在的转换时添加其他可区分的属性,以确保仅选择单个链来满足请求
-
请求其他属性以消除歧义,确定选择哪个链(如果它们导致非相同的最终属性)
-
从构建中删除不必要的已注册转换
这将在 Gradle 9.0 中成为错误。
init
必须单独运行
init
任务必须单独运行。此任务不应与单个 Gradle 调用中的其他任务组合在一起。
在与其他任务相同的调用中运行 init
将在 Gradle 9.0 中成为错误。
例如,这不被允许
> gradlew init tasks
从任务操作中调用 Task.getProject()
现在已弃用在执行时从任务操作中调用 Task.getProject(),并且将在 Gradle 10.0 中成为错误。此方法仍然可以在配置时使用。
仅当未启用配置缓存时,才会发出弃用。当启用配置缓存时,对 Task.getProject() 的调用将报告为配置缓存问题。
此弃用最初在 Gradle 7.4 中引入,但仅在启用 STABLE_CONFIGURATION_CACHE
功能标志时才会发出。该功能标志不再控制此弃用。这是朝着使用户远离与配置缓存不兼容的习惯用法的又一步,配置缓存将在未来的版本中成为 Gradle 支持的唯一模式。
请参阅配置缓存文档,了解在执行时调用 Task.getProject()
的替代方案,这些方案与配置缓存兼容。
Groovy “空格赋值” 语法
当前,有多种使用 Groovy DSL 语法设置属性的方法
---
propertyName = value
setPropertyName(value)
setPropertyName value
propertyName(value)
propertyName value
---
后者“空格赋值”是 Gradle 特有的功能,不是 Groovy 语言的一部分。在常规 Groovy 中,这只是一个方法调用:propertyName(value)
,如果 Gradle 运行时中尚不存在 propertyName
方法,则 Gradle 会生成该方法。此功能可能会引起混淆(尤其是对于新用户),并为用户和 Gradle 代码库增加了一层额外的复杂性,而没有提供任何显着的价值。有时,类声明的方法名称相同,甚至可能具有与纯赋值不同的语义。
这些生成的方法现在已弃用,将在 Gradle 10.0 中删除,并且 propertyName value
和 propertyName(value)
都将停止工作,除非定义了显式方法 propertyName
。请改用显式赋值 propertyName = value
。
对于显式方法,请考虑使用 propertyName(value)
语法而不是 propertyName value
以提高清晰度。例如,jvmArgs "some", "arg"
可以替换为 jvmArgs("some", "arg")
或 jvmArgs = ["some", "arg"]
用于 Test
任务。
如果您有一个大型项目,要替换空格赋值语法的出现,可以使用例如以下 sed
命令
---
find . -name 'build.gradle' -type f -exec sed -i.bak -E 's/([^A-Za-z]|^)(replaceme)[ \t]*([^= \t{])/\1\2 = \3/g' {} +
---
您应该将 replaceme
替换为一个或多个要替换的属性名称,以 |
分隔,例如 (url|group)
。
DependencyInsightReportTask.getDependencySpec
该方法已弃用,因为它不打算在构建脚本中公开使用。
ReportingExtension.baseDir
ReportingExtension.getBaseDir()
、`ReportingExtension.setBaseDir(File)
和 ReportingExtension.setBaseDir(Object)
已弃用。它们应替换为 ReportingExtension.getBaseDirectory()
属性。
从 8.10 及更早版本升级
潜在的破坏性变更
升级到 Kotlin 2.0.20
嵌入式 Kotlin 已从 1.9.24 更新到 Kotlin 2.0.20。另请参阅 Kotlin 2.0.10 和 Kotlin 2.0.0 发行说明。
JVM 测试套件中的默认 kotlin-test
版本也已升级到 2.0.20。
Kotlin DSL 脚本仍然使用 Kotlin 语言版本设置为 1.8 进行编译,以实现向后兼容性。
通过工具链配置 Gradle 守护进程 JVM
属性 UpdateDaemonJvm.jvmVersion
的类型现在是 Property<JavaLanguageVersion>
。
如果您在构建脚本中配置了任务,则需要替换
jvmVersion = JavaVersion.VERSION_17
替换为
jvmVersion = JavaLanguageVersion.of(17)
使用 CLI 选项配置 Gradle 守护进程要使用的 JVM 版本没有影响。
名称匹配更改
名称匹配逻辑已更新,将数字视为驼峰式名称的单词边界。以前,像 unique
这样的请求会同时匹配 uniqueA
和 unique1
。此类请求现在将因歧义而失败。为避免问题,请使用确切的名称而不是缩短的版本。
此更改影响
-
任务选择
-
项目选择
-
依赖报告任务中的配置选择
弃用
ForkOptions 的已弃用 JavaHome 属性
ForkOptions
类型的 JavaHome 属性已被弃用,将在 Gradle 9.0 中删除。
请改用 JVM 工具链,或 executable 属性。
已弃用更改 buildscript 配置
从 Gradle 9.0 开始,在脚本的 buildscript 块中更改配置将导致错误。这适用于项目、设置、初始化和独立脚本。
buildscript 配置块仅用于控制 buildscript 类路径解析。
考虑以下脚本,该脚本在 Settings 脚本中创建新的 buildscript 配置并解析它
buildscript {
configurations {
create("myConfig")
}
dependencies {
"myConfig"("org:foo:1.0")
}
}
val files = buildscript.configurations["myConfig"].files
此模式有时用于解析 Settings 中的依赖项,因为没有其他方法可以获取 Configuration。不建议在此上下文中解析依赖项。使用分离的配置是一种可能的但并不推荐的替代方案。
上面的示例可以修改为使用分离的配置
val myConfig = buildscript.configurations.detachedConfiguration(
buildscript.dependencies.create("org:foo:1.0")
)
val files = myConfig.files
按配置名称选择 Maven 变体
从 Gradle 9.0 开始,将禁止从非 Ivy 外部组件按名称选择变体。
仍然允许从本地组件按名称选择变体;但是,不鼓励使用此模式。对于本地组件,应优先使用变体感知依赖项解析,而不是按名称选择变体。
当以非 Ivy 外部组件为目标时,以下依赖项将无法解析
dependencies {
implementation(group: "com.example", name: "example", version: "1.0", configuration: "conf")
implementation("com.example:example:1.0") {
targetConfiguration = "conf"
}
}
已弃用手动添加到配置容器
从 Gradle 9.0 开始,手动将配置实例添加到配置容器将导致错误。配置应仅通过 eager 或 lazy 工厂方法添加到容器。分离的配置和复制的配置不应添加到容器。
将禁止在 ConfigurationContainer 上调用以下方法:- add(Configuration) - addAll(Collection) - addLater(Provider) - addAllLater(Provider)
已弃用 ProjectDependency#getDependencyProject()
ProjectDependency#getDependencyProject()
方法已弃用,将在 Gradle 9.0 中删除。
应避免访问其他项目的可变项目实例。
要发现有关解析中包含的所有项目的详细信息,请检查完整的 ResolutionResult。项目依赖项在 DependencyResult 中公开。有关此 API 的更多详细信息,请参阅用户指南中关于程序化依赖项解析的部分。这是查找解析中使用的所有项目的唯一可靠方法。仅检查声明的 `ProjectDependency` 可能会遗漏传递或替换的项目依赖项。
要获取目标项目的标识,请使用新的隔离项目安全项目路径方法:ProjectDependency#getPath()
。
要访问或配置目标项目,请考虑以下直接替换
val projectDependency: ProjectDependency = getSomeProjectDependency()
// Old way:
val someProject = projectDependency.dependencyProject
// New way:
val someProject = project.project(projectDependency.path)
此方法不会从不同的构建中获取项目实例。
已弃用 ResolvedConfiguration.getFiles()
和 LenientConfiguration.getFiles()
ResolvedConfiguration.getFiles() 和 LenientConfiguration.getFiles() 方法已弃用,将在 Gradle 9.0 中删除。
这些已弃用的方法不跟踪任务依赖项,这与它们的替代方法不同。
val deprecated: Set<File> = conf.resolvedConfiguration.files
val replacement: FileCollection = conf.incoming.files
val lenientDeprecated: Set<File> = conf.resolvedConfiguration.lenientConfiguration.files
val lenientReplacement: FileCollection = conf.incoming.artifactView {
isLenient = true
}.files
已弃用 AbstractOptions
AbstractOptions
类已弃用,将在 Gradle 9.0 中删除。所有扩展 AbstractOptions
的类将不再扩展它。
因此,AbstractOptions#define(Map)
方法将不再存在。此方法公开了一个非类型安全 API,并且不必要地依赖于反射。它可以替换为直接设置 map 中指定的属性。
此外,依赖于 define
的 CompileOptions#fork(Map)
、CompileOptions#debug(Map)
和 GroovyCompileOptions#fork(Map)
也已弃用,将在 Gradle 9.0 中删除。
考虑以下已弃用行为的示例及其替换
tasks.withType(JavaCompile) {
// Deprecated behavior
options.define(encoding: 'UTF-8')
options.fork(memoryMaximumSize: '1G')
options.debug(debugLevel: 'lines')
// Can be replaced by
options.encoding = 'UTF-8'
options.fork = true
options.forkOptions.memoryMaximumSize = '1G'
options.debug = true
options.debugOptions.debugLevel = 'lines'
}
已弃用 Dependency#contentEquals(Dependency)
Dependency#contentEquals(Dependency) 方法已弃用,将在 Gradle 9.0 中删除。
该方法最初旨在根据依赖项的实际目标组件进行比较,而不管它们是否属于不同的依赖项类型。现有方法的行为与其 Javadoc 指定的行为不符,我们不计划引入替代方法。
可能的迁移包括直接使用 Object.equals(Object)
,或手动比较依赖项的字段。
已弃用 Project#exec
和 Project#javaexec
Project#exec(Closure)、Project#exec(Action)、Project#javaexec(Closure)、Project#javaexec(Action) 方法已弃用,将在 Gradle 9.0 中删除。
计划删除这些方法,作为使编写与配置缓存兼容的代码更容易的持续工作的一部分。在不违反配置缓存要求的情况下,无法使用这些方法,因此建议迁移到兼容的替代方案。您的用例的适当替代方案取决于先前调用该方法的上下文。
在执行时,例如在 @TaskAction
或 doFirst
/doLast
回调中,启用配置缓存时不允许使用 Project
实例。要运行外部进程,任务应使用注入的 ExecOperation
服务,该服务具有相同的 API,并且可以充当直接替换。标准 Java/Groovy/Kotlin 进程 API,如 java.lang.ProcessBuilder
也可以使用。
在配置时,仅当启用配置缓存时,才必须使用特殊的基于 Provider 的 API 来运行外部进程。您可以使用 ProviderFactory.exec
和 ProviderFactory.javaexec
来获取进程的输出。自定义 ValueSource
实现可用于更复杂的场景。配置缓存指南提供了一个更详细的使用这些 API 的示例。
分离的配置不应使用 extendsFrom
分离的配置不应使用 extendsFrom
扩展其他配置。
此行为已被弃用,将在 Gradle 9.0 中成为错误。
要创建配置之间的扩展关系,您应该改为使用通过项目 ConfigurationContainer
中提供的其他工厂方法创建的非分离配置。
已弃用自定义 Gradle 日志记录
Gradle#useLogger(Object)
方法已弃用,将在 Gradle 9.0 中移除。
此方法最初旨在自定义 Gradle 打印的日志。但是,它只允许拦截一部分日志,并且无法与配置缓存一起使用。我们不计划为此功能引入替代方案。
编译选项和文档任务上不必要的选项已被弃用
Gradle 的 API 允许使用 setter 方法整体替换某些表示嵌套属性组的属性。这样做既笨拙又不常见,有时还需要使用内部 API。这些属性的 setter 将在 Gradle 9.0 中移除,以简化 API 并确保行为一致。应该通过调用 getter 并直接配置对象,或使用便捷的配置方法来配置这些属性,而不是使用 setter 方法。例如,在 CompileOptions
中,您可以调用 getForkOptions()
或 forkOptions(Action)
,而不是调用 setForkOptions
setter。
受影响的属性包括
已弃用 Javadoc.isVerbose()
和 Javadoc.setVerbose(boolean)
Javadoc
上的这些方法已弃用,将在 Gradle 9.0 中移除。
-
调用
setVerbose(boolean)
且参数为true
已被getOptions().verbose()
替代 -
调用
setVerbose(false)
不会执行任何操作。
从 8.9 及更早版本升级
潜在的破坏性变更
即使不需要编译,使用 JRE 时 JavaCompile
任务也可能失败
当使用 JRE 而不是 JDK 时,JavaCompile
任务有时可能会失败。这是由于工具链解析代码中的更改,该代码在请求编译器时强制要求编译器的存在。当未设置 sourceCompatibility
/targetCompatibility
或 release
时,java-base
插件使用它创建的 JavaCompile
任务来确定默认的源和目标兼容性。由于新的强制执行,即使不需要编译(例如,在没有源文件的项目中),仅提供 JRE 时,缺少编译器也会导致此操作失败。
可以通过在 java
扩展中显式设置 sourceCompatibility
/targetCompatibility
,或者在相关的任务中设置 sourceCompatibility
/targetCompatibility
或 release
来解决此问题。
升级到 Kotlin 1.9.24
嵌入式 Kotlin 已从 1.9.23 更新到 Kotlin 1.9.24。
升级到 Ant 1.10.14
Ant 已更新到 Ant 1.10.14。
升级到 JaCoCo 0.8.12
JaCoCo 已更新到 0.8.12。
升级到 Groovy 3.0.22
Groovy 已更新到 Groovy 3.0.22。
弃用
在较旧的 JVM 上运行 Gradle
从 Gradle 9.0 开始,Gradle 将需要 JVM 17 或更高版本才能运行。大多数 Gradle API 将被编译为目标 JVM 17 字节码。
Gradle 仍将支持将 Java 代码编译为目标 JVM 版本 6 或更高版本。编译代码的目标 JVM 版本可以与用于运行 Gradle 的 JVM 版本分开配置。
所有 Gradle 客户端(wrapper、launcher、Tooling API 和 TestKit)将继续与 JVM 8 兼容,并将被编译为目标 JVM 8 字节码。只有 Gradle 守护程序将需要 JVM 17 或更高版本。这些客户端可以配置为使用与运行客户端的 JVM 版本不同的 JVM 版本来运行 Gradle 构建
-
使用 守护程序 JVM 标准(一项孵化功能)
-
设置
org.gradle.java.home
Gradle 属性 -
在 Tooling API 上使用
ConfigurableLauncher#setJavaHome
方法
或者,可以将 JAVA_HOME
环境变量设置为 JVM 17 或更高版本,这将使用相同版本的 JVM 运行客户端和守护程序。
使用 --no-daemon
或在测试中使用 ProjectBuilder
运行 Gradle 构建将需要 JVM 版本 17 或更高版本。worker API 将继续与 JVM 8 兼容,而运行 JVM 测试将需要 JVM 8。
我们决定升级 Java 运行时的最低版本,原因如下
-
依赖项开始放弃对旧版本的支持,并且可能不会发布安全补丁。
-
如果不升级,则无法使用 Java 8 和 Java 17 之间显着的语言改进。
-
一些最流行的插件已经需要 JVM 17 或更高版本。
-
Gradle 发行版的下载指标表明 JVM 17 已被广泛使用。
已弃用从 Ivy 使用不可消费的配置
在 Gradle 的早期版本中,可以使用已发布的 Ivy 元数据来使用项目的不可消费配置。Ivy 依赖项有时可以替换为项目依赖项,可以通过 DependencySubstitutions
API 显式替换,也可以通过包含的构建隐式替换。发生这种情况时,可以选择替换项目中标记为不可消费的配置。
以这种方式使用不可消费的配置已被弃用,并且会在 Gradle 9.0 中导致错误。
已弃用在同一项目中扩展配置
在 Gradle 的早期版本中,可以扩展不同项目中的配置。
项目的配置层次结构不应受其他项目中配置的影响。当以配置所有者不希望的方式扩展配置时,跨项目层次结构可能会导致意外行为。
项目也不应访问另一个项目的可变状态。由于配置是可变的,因此跨项目边界扩展配置会限制 Gradle 可以应用的并行性。
在不同项目中扩展配置已被弃用,并且会在 Gradle 9.0 中导致错误。
从 8.8 及更早版本升级
潜在的破坏性变更
工具链配置的变更
在 Gradle 的早期版本中,工具链配置可能会将部分配置的工具链留在原位,并带有一个标记文件,指示工具链已完全配置。这可能会导致工具链出现奇怪的行为。在 Gradle 8.9 中,工具链在写入标记文件之前已完全配置。但是,为了不检测潜在的损坏工具链,使用了不同的标记文件 (.ready
)。这意味着您现有的所有工具链将在您首次在 Gradle 8.9 中使用它们时重新配置。Gradle 8.9 还会写入旧的标记文件 (provisioned.ok
),以指示工具链已完全配置。这意味着,如果您返回到旧版本的 Gradle,则 8.9 配置的工具链将不会重新配置。
升级到 Kotlin 1.9.23
嵌入式 Kotlin 已从 1.9.22 更新到 Kotlin 1.9.23。
更改守护程序日志文件的编码
在 Gradle 的早期版本中,守护程序日志文件(位于 $GRADLE_USER_HOME/daemon/8.13/
)使用默认的 JVM 编码进行编码。此文件现在始终使用 UTF-8 编码,以防止可能使用不同默认编码的客户端错误地读取数据。此更改可能会影响尝试读取此文件的第三方工具。
针对 Gradle 实现类路径进行编译
在 Gradle 的早期版本中,没有声明依赖项的 Java 项目可以隐式地针对 Gradle 的运行时类进行编译。这意味着,即使某些项目引用了 Gradle 运行时类,它们也能够在没有任何声明依赖项的情况下进行编译。这种情况不太可能在项目中发生,因为 IDE 集成和测试执行将受到影响。但是,如果您需要使用 Gradle API,请声明 gradleApi
依赖项或应用 java-gradle-plugin
插件。
配置缓存实现包现在位于 org.gradle.internal
下
应避免引用不属于公共 API 的 Gradle 类型,因为不支持直接使用它们。Gradle 内部实现类可能会发生破坏性变更(或被重命名或移除),恕不另行通知。
用户需要区分 Gradle 代码库的 API 部分和内部部分。这通常通过在实现包名称中包含 internal
来实现。但是,在此版本之前,配置缓存子系统未遵循此模式。
为了解决此问题,最初位于 org.gradle.configurationcache*
包下的所有代码都已移至新的内部包 (org.gradle.internal.*
)。
macOS 11 (Big Sur) 及更早版本上的文件系统监视已禁用
自 Gradle 8.8 以来,文件系统监视仅在 macOS 12 (Monterey) 及更高版本上受支持。我们添加了一项检查,以在 macOS 11 (Big Sur) 及更早版本上自动禁用文件系统监视。
使用注解处理器时,基于 JDK8 的编译器输出可能发生更改
Java 编译基础结构已更新为使用 Problems API。此更改将为 Tooling API 客户端提供关于编译问题的结构化、丰富的信息。
此功能不应对通常的构建输出产生任何可见的影响,JDK8 除外。当编译器中使用注解处理器时,输出消息与之前的消息略有不同。
此更改主要体现在打印的类型名称中。例如,Java 标准类型(如 java.lang.String
)将报告为 java.lang.String
而不是 String
。
从 8.7 及更早版本升级
弃用
弃用在观察后修改配置
为了确保依赖项解析的准确性,Gradle 会检查在用作依赖项图的一部分后是否修改了配置。
-
可解析的配置在解析后不应修改其解析策略、依赖项、层次结构等。
-
可消费的配置在发布或作为变体消费后不应修改其依赖项、层次结构、属性等。
-
依赖项范围配置在观察到从中扩展的配置后,不应修改其依赖项、约束等。
在 Gradle 的早期版本中,许多这些情况被检测到并通过使构建失败来处理。但是,有些情况未被检测到或未触发构建失败。在 Gradle 9.0 中,一旦观察到对配置的所有更改,都将变为错误。观察到任何类型的配置后,都应将其视为不可变的。此验证涵盖配置的以下属性
-
解析策略
-
依赖项
-
约束
-
排除规则
-
工件
-
角色(可消费、可解析、依赖项范围)
-
层次结构 (
extendsFrom
) -
其他(传递性、可见性)
从 Gradle 8.8 开始,在尚未出错的情况下,将发出弃用警告。通常,此弃用是由在 beforeResolve
挂钩中修改配置引起的。此挂钩仅在配置完全解析后执行,而不是在部分解析配置以计算任务依赖项时执行。
请考虑以下代码,该代码展示了已弃用的行为
plugins {
id("java-library")
}
configurations.runtimeClasspath {
// `beforeResolve` is not called before the configuration is partially resolved for
// build dependencies, but only before a full graph resolution.
// Configurations should not be mutated in this hook
incoming.beforeResolve {
// Add a dependency on `com:foo` if not already present
if (allDependencies.none { it.group == "com" && it.name == "foo" }) {
configurations.implementation.get().dependencies.add(project.dependencies.create("com:foo:1.0"))
}
}
}
tasks.register("resolve") {
val conf: FileCollection = configurations["runtimeClasspath"]
// Wire build dependencies
dependsOn(conf)
// Resolve dependencies
doLast {
assert(conf.files.map { it.name } == listOf("foo-1.0.jar"))
}
}
对于以下用例,请考虑在替换 beforeResolve
挂钩时使用以下替代方案
-
添加依赖项:在
DependencySet
上使用DependencyFactory
和addLater
或addAllLater
。 -
更改依赖项版本:使用首选版本约束。
-
添加排除项:使用 组件元数据规则来调整依赖项级别的排除项,或使用
withDependencies
向配置添加排除项。 -
角色:配置角色应在创建时设置,之后不得更改。
-
层次结构:配置层次结构 (
extendsFrom
) 应在创建时设置。强烈建议不要在解析之前修改层次结构,但在withDependencies
挂钩中允许修改。 -
解析策略:仍然允许在
beforeResolve
挂钩中修改配置的 ResolutionStrategy;但是,不建议这样做。
已弃用过滤配置 file
和 fileCollection
方法
为了持续简化 Gradle API,以下支持基于声明的依赖项进行过滤的方法已被弃用
在 Configuration
上
-
files(Dependency…)
-
files(Spec)
-
files(Closure)
-
fileCollection(Dependency…)
-
fileCollection(Spec)
-
fileCollection(Closure)
-
getFiles(Spec)
-
getFirstLevelModuleDependencies(Spec)
-
getFirstLevelModuleDependencies(Spec)
-
getFiles(Spec)
-
getArtifacts(Spec)
为了缓解此弃用,请考虑以下示例,该示例利用 ArtifactView
API 以及 componentFilter
方法来选择配置工件的子集
val conf by configurations.creating
dependencies {
conf("com.thing:foo:1.0")
conf("org.example:bar:1.0")
}
tasks.register("filterDependencies") {
val files: FileCollection = conf.incoming.artifactView {
componentFilter {
when(it) {
is ModuleComponentIdentifier ->
it.group == "com.thing" && it.module == "foo"
else -> false
}
}
}.files
doLast {
assert(files.map { it.name } == listOf("foo-1.0.jar"))
}
}
configurations {
conf
}
dependencies {
conf "com.thing:foo:1.0"
conf "org.example:bar:1.0"
}
tasks.register("filterDependencies") {
FileCollection files = configurations.conf.incoming.artifactView {
componentFilter {
it instanceof ModuleComponentIdentifier
&& it.group == "com.thing"
&& it.module == "foo"
}
}.files
doLast {
assert files*.name == ["foo-1.0.jar"]
}
}
与已弃用的 Dependency
过滤方法相反,componentFilter
不考虑被过滤组件的传递依赖项。这允许对选择哪些工件进行更精细的控制。
已弃用 Task
和 Configuration
的 Namer
Task
和 Configuration
具有一个 Namer
内部类(也称为 Namer
),可以用作检索任务或配置名称的通用方法。现在这些类型实现了 Named
,这些类不再是必需的,并且已被弃用。它们将在 Gradle 9.0 中移除。请改用 Named.Namer.INSTANCE
。
超级接口 Namer
未被弃用。
已弃用直接在本地构建缓存上设置保留期
在之前的版本中,本地构建缓存条目的清理每 24 小时运行一次,并且无法配置此间隔。保留期是使用 buildCache.local.removeUnusedEntriesAfterDays
配置的。
在 Gradle 8.0 中,添加了一种新机制来配置 Gradle 用户主目录中各种资源的清理和保留期。在 Gradle 8.8 中,此机制已扩展为允许本地构建缓存条目的保留配置,从而提供改进的控制和一致性。
-
指定
Cleanup.DISABLED
或Cleanup.ALWAYS
现在将阻止或强制清理本地构建缓存 -
构建缓存条目保留现在通过
init-script
进行配置,方式与其他缓存相同。
如果您希望将构建缓存条目保留 30 天,请移除对已弃用方法的所有调用
buildCache {
local {
// Remove this line
removeUnusedEntriesAfterDays = 30
}
}
在 ~/.gradle/init.d
中添加如下文件
beforeSettings {
caches {
buildCache.setRemoveUnusedEntriesAfterDays(30)
}
}
调用 buildCache.local.removeUnusedEntriesAfterDays
已弃用,此方法将在 Gradle 9.0 中移除。如果设置为非默认值,则此已弃用的设置将优先于 Settings.caches.buildCache.setRemoveUnusedEntriesAfterDays()
。
已弃用 Kotlin DSL gradle-enterprise 插件块扩展
在 settings.gradle.kts
(Kotlin DSL) 中,您可以使用插件块中的 gradle-enterprise
来应用 Gradle Enterprise 插件,其版本与 gradle --scan
相同。
plugins {
`gradle-enterprise`
}
在 settings.gradle
(Groovy DSL) 中没有等效项。
Gradle Enterprise 已重命名为 Develocity,com.gradle.enterprise
插件已重命名为 com.gradle.develocity
。因此,gradle-enterprise
插件块扩展已被弃用,将在 Gradle 9.0 中移除。
Develocity 插件必须使用显式的插件 ID 和版本应用。插件块中没有可用的 develocity
简写
plugins {
id("com.gradle.develocity") version "3.17.3"
}
如果您想继续使用 Gradle Enterprise 插件,可以指定已弃用的插件 ID
plugins {
id("com.gradle.enterprise") version "3.17.3"
}
我们建议您使用最新发布的 Develocity 插件版本,即使在使用旧版本的 Gradle 时也是如此。
潜在的破坏性变更
Problems API 中的变更
我们已经实现了 Problems API 的多项重构,包括问题定义和上下文信息的处理方式的重大变更。完整的设计规范可以在此处找到。
在实现此规范时,我们对 ProblemSpec
接口引入了以下破坏性变更
-
label(String)
和description(String)
方法已被id(String, String)
方法及其重载变体替换。
集合属性的变更
已移除 8.7 中引入的以下孵化 API
-
MapProperty.insert*(…)
-
HasMultipleValues.append*(…)
正在考虑使用更好地处理约定的替代方案,以用于未来的 8.x 版本。
升级到 Groovy 3.0.21
Groovy 已更新到 Groovy 3.0.21。
静态类型检查中的一些更改导致了源代码不兼容。从 3.0.18 开始,如果您将闭包强制转换为没有泛型的 Action
,则闭包参数将是 Object
,而不是任何指定的显式类型。可以通过向强制转换添加适当的类型来解决此问题,并且可以移除冗余的参数声明
// Before
tasks.create("foo", { Task it -> it.description = "Foo task" } as Action)
// Fixed
tasks.create("foo", { it.description = "Foo task" } as Action<Task>)
升级到 ASM 9.7
ASM 从 9.6 升级到 9.7,以确保更早地兼容 Java 23。
从 8.6 及更早版本升级
潜在的破坏性变更
升级到 Kotlin 1.9.22
嵌入式 Kotlin 已从 1.9.10 更新到 Kotlin 1.9.22。
升级到 Apache SSHD 2.10.0
Apache SSHD 已从 2.0.0 更新到 2.10.0。
升级到 Eclipse JGit 5.13.3
Eclipse JGit 已从 5.7.0 更新到 5.13.3。
这包括通过从 JSch 迁移到 Apache SSHD,重新设计 Gradle 为 SSH 操作配置 JGit 的方式。
升级到 Apache Commons Compress 1.25.0
Apache Commons Compress 已从 1.21 更新到 1.25.0。此更改可能会影响生成的 jar、zip 和其他归档类型的校验和,因为生成的工件的元数据可能有所不同。
升级到 ASM 9.6
ASM 从 9.5 升级到 9.6,以更好地支持多版本 jar。
弃用
已弃用插件约定的注册
自 Gradle 8.2 以来,使用插件约定一直在发出警告。现在,注册插件约定也会触发弃用警告。有关更多信息,请参阅关于插件约定弃用的部分。
在 Kotlin DSL 中通过 "name"()
引用任务和域对象
在 Kotlin DSL 中,可以使用 "name"()
表示法通过名称引用任务或其他域对象。
有几种方法可以通过名称查找容器中的元素
tasks {
"wrapper"() // 1 - returns TaskProvider<Task>
"wrapper"(Wrapper::class) // 2 - returns TaskProvider<Wrapper>
"wrapper"(Wrapper::class) { // 3 - configures a task named wrapper of type Wrapper
}
"wrapper" { // 4 - configures a task named wrapper of type Task
}
}
第一个表示法已被弃用,将在 Gradle 9.0 中移除。请使用 named("name")
或其他受支持的表示法之一,而不是使用 "name"()
引用任务或域对象。
上面的示例将写为
tasks {
named("wrapper") // returns TaskProvider<Task>
}
Gradle API 和 Groovy 构建脚本不受此影响。
已弃用无效的 URL 解码行为
在 Gradle 8.3 之前,Gradle 会使用一种算法解码提供给 Project.uri(Object)
的 CharSequence
,该算法接受无效的 URL 并错误地解码其他 URL。Gradle 现在使用 URI
类来解析和解码 URL,但在发生错误时会回退到旧的行为。
从 Gradle 9.0 开始,回退将被移除,并且会改为抛出错误。
要修复弃用警告,需要旧行为的无效 URL 应重新编码为有效的 URL,如下例所示
原始输入 | 新输入 | 理由 |
---|---|---|
|
|
|
|
|
如果没有方案,则路径按原样获取,无需解码。 |
|
空格在 URL 中无效。 |
|
|
||
file::somepath |
somepath |
URI 应为分层结构。 |
已弃用 SelfResolvingDependency
SelfResolvingDependency
接口已被弃用,将在 Gradle 9.0 中移除。此类型可以追溯到 Gradle 的第一个版本,在这些版本中,某些依赖项可以独立解析。现在,所有依赖项都应使用 Configuration
作为依赖项图的一部分进行解析。
目前,ProjectDependency
和 FileCollectionDependency
实现了此接口。在 Gradle 9.0 中,这些类型将不再实现 SelfResolvingDependency
。相反,它们都将直接实现 Dependency
。
因此,ProjectDependency
和 FileCollectionDependency
的以下方法将不再可用
-
resolve
-
resolve(boolean)
-
getBuildDependencies
请考虑以下脚本,这些脚本展示了已弃用的接口及其替代方案
plugins {
id("java-library")
}
dependencies {
implementation(files("bar.txt"))
implementation(project(":foo"))
}
tasks.register("resolveDeprecated") {
// Wire build dependencies (calls getBuildDependencies)
dependsOn(configurations["implementation"].dependencies.toSet())
// Resolve dependencies
doLast {
configurations["implementation"].dependencies.withType<FileCollectionDependency>() {
assert(resolve().map { it.name } == listOf("bar.txt"))
assert(resolve(true).map { it.name } == listOf("bar.txt"))
}
configurations["implementation"].dependencies.withType<ProjectDependency>() {
// These methods do not even work properly.
assert(resolve().map { it.name } == listOf<String>())
assert(resolve(true).map { it.name } == listOf<String>())
}
}
}
tasks.register("resolveReplacement") {
val conf = configurations["runtimeClasspath"]
// Wire build dependencies
dependsOn(conf)
// Resolve dependencies
val files = conf.files
doLast {
assert(files.map { it.name } == listOf("bar.txt", "foo.jar"))
}
}
从 8.5 及更早版本升级
潜在的破坏性变更
升级到 JaCoCo 0.8.11
JaCoCo 已更新到 0.8.11。
DependencyAdder
重命名为 DependencyCollector
孵化中的 DependencyAdder
接口已重命名为 DependencyCollector
。接口中添加了一个 getDependencies
方法,该方法返回所有声明的依赖项。
弃用
已弃用使用 main
源集调用 registerFeature
在 java
扩展上使用 main
源集调用 registerFeature
已弃用,并且将在 Gradle 9.0 中更改行为。
目前,在使用 main
源集调用 usingSourceSet
时创建的功能与在使用任何其他源集调用 usingSourceSet
时创建的功能的初始化方式不同。以前,当使用 main
源集时,会创建新的 implementation
、compileOnly
、runtimeOnly
、api
和 compileOnlyApi
配置,并且 main
源集的编译和运行时类路径被配置为扩展这些配置。
从 Gradle 9.0 开始,main
源集将像任何其他源集一样对待。应用 java-library
插件(或任何其他应用 java
插件的插件)后,使用 main
源集调用 usingSourceSet
将抛出异常。这是因为 java
插件已经配置了 main
功能。仅当未应用 java
插件时,才允许在调用 usingSourceSet
时使用 main
源集。
代码目前向主源码集注册功能,例如
plugins {
id("java-library")
}
java {
registerFeature("feature") {
usingSourceSet(sourceSets["main"])
}
}
plugins {
id("java-library")
}
java {
registerFeature("feature") {
usingSourceSet(sourceSets.main)
}
}
应该改为为该功能创建一个单独的源码集,并将该功能注册到该源码集
plugins {
id("java-library")
}
sourceSets {
create("feature")
}
java {
registerFeature("feature") {
usingSourceSet(sourceSets["feature"])
}
}
plugins {
id("java-library")
}
sourceSets {
feature
}
java {
registerFeature("feature") {
usingSourceSet(sourceSets.feature)
}
}
已弃用:发布具有与 artifactId 不同的显式名称的构件依赖项到 Maven 仓库
发布具有与依赖项的 artifactId
不同的显式构件名称的依赖项到 Maven 仓库已被弃用。当发布到 Ivy 仓库时,此行为仍然允许。在 Gradle 9.0 中,这将导致错误。
当发布到 Maven 仓库时,Gradle 将把下面的依赖项解释为使用坐标 org:notfoo:1.0
声明的依赖项
dependencies {
implementation("org:foo:1.0") {
artifact {
name = "notfoo"
}
}
}
dependencies {
implementation("org:foo:1.0") {
artifact {
name = "notfoo"
}
}
}
相反,此依赖项应声明为
dependencies {
implementation("org:notfoo:1.0")
}
dependencies {
implementation("org:notfoo:1.0")
}
已弃用 ArtifactIdentifier
ArtifactIdentifier
类已被弃用,将在 Gradle 9.0 中移除。
弃用:在观察后修改 DependencyCollector
依赖项
从 Gradle 9.0 开始,在从 DependencyCollector 获取的依赖项被观察后对其进行修改将导致错误。DependencyCollector
接口用于在测试套件 DSL 中声明依赖项。
考虑以下示例,其中测试套件的依赖项在被观察后被修改
plugins {
id("java-library")
}
testing.suites {
named<JvmTestSuite>("test") {
dependencies {
// Dependency is declared on a `DependencyCollector`
implementation("com:foo")
}
}
}
configurations.testImplementation {
// Calling `all` here realizes/observes all lazy sources, including the `DependencyCollector`
// from the test suite block. Operations like resolving a configuration similarly realize lazy sources.
dependencies.all {
if (this is ExternalDependency && group == "com" && name == "foo" && version == null) {
// Dependency is mutated after observation
version {
require("2.0")
}
}
}
}
在上面的示例中,构建逻辑使用迭代和修改来尝试为特定依赖项设置默认版本(如果尚未设置版本)。像上面示例这样的构建逻辑在解析声明的依赖项时会产生挑战,因为报告工具会将此依赖项显示为用户声明了版本 "2.0",即使他们从未这样做过。相反,构建逻辑可以通过在依赖项的坐标上声明 preferred
版本约束来避免迭代和修改。这允许依赖项管理引擎在没有声明其他版本的情况下使用约束上声明的版本。
考虑以下示例,该示例用不加区分的 preferred 版本约束替换了上面的迭代
dependencies {
constraints {
testImplementation("com:foo") {
version {
prefer("2.0")
}
}
}
}
从 8.4 及更早版本升级
潜在的破坏性更改
升级到 Kotlin 1.9.20
嵌入式 Kotlin 已更新至 Kotlin 1.9.20。
Groovy 任务约定的更改
groovy-base
插件现在负责在所有 GroovyCompile
任务上配置源和目标兼容性版本约定。
如果您在未应用 groovy-base
的情况下使用此任务,则必须手动在这些任务上设置兼容性版本。通常,在处理 Groovy 语言任务时,应始终应用 groovy-base
插件。
Provider.filter
传递给 Provider.filter
的参数类型从 Predicate
更改为 Spec
,以便 API 更加一致。此更改不应影响任何使用带有 lambda 表达式的 Provider.filter
的用户。但是,如果插件作者不使用 SAM 转换来创建 lambda,则可能会受到影响。
弃用
org.gradle.util
包中已弃用的成员现在报告其弃用
这些成员将在 Gradle 9.0 中移除
-
VersionNumber.parse(String)
-
VersionNumber.compareTo(VersionNumber)
已弃用:依赖于已解析的配置
当解析 Configuration
时,有时可以选择将同一配置作为变体。配置应仅用于一个目的(解析、消费或依赖项声明),因此这种情况仅在配置标记为既可消费又可解析时才会发生。
这可能会导致循环依赖关系图,因为已解析的配置用于两个目的。
为了避免此问题,插件应将所有可解析配置标记为 canBeConsumed=false
,或者在使用配置工厂方法 resolvable(String)
创建用于解析的配置时使用该方法。
在 Gradle 9.0 中,将不再允许以这种方式消费配置,并将导致错误。
包含没有现有目录的项目
如果将项目添加到构建中,但关联的 projectDir
不存在或不可写,Gradle 将发出警告。从 9.0 版本开始,如果项目目录丢失或只读,Gradle 将不会运行构建。如果您打算动态合成项目,请确保也为其创建目录
include("project-without-directory")
project(":project-without-directory").projectDir.mkdirs()
include 'project-without-directory'
project(":project-without-directory").projectDir.mkdirs()
从 8.3 及更早版本升级
潜在的破坏性更改
升级到 Kotlin 1.9.10
嵌入式 Kotlin 已更新至 Kotlin 1.9.10。
XML 解析现在需要最新的解析器
Gradle 8.4 现在配置了启用安全功能的 XML 解析器。如果您的构建逻辑依赖于不支持安全解析的旧 XML 解析器,则您的构建可能会失败。如果遇到故障,请检查并更新或删除对旧 XML 解析器的任何依赖项。
如果您是 Android 用户,请将您的 AGP 版本升级到 8.3.0 或更高版本,以修复 AGP 本身导致的问题。有关更多详细信息,请参阅 更新 AGP 中用于 Gradle 8.4 兼容性的 XML 解析器。
如果您无法升级来自构建逻辑依赖项的 XML 解析器,您可以强制使用 JVM 内置的 XML 解析器。例如,在 OpenJDK 中,可以通过将以下内容添加到 gradle.properties
来完成此操作
systemProp.javax.xml.parsers.SAXParserFactory=com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl
systemProp.javax.xml.transform.TransformerFactory=com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl
systemProp.javax.xml.parsers.DocumentBuilderFactory=com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl
有关更多详细信息以及在以前的 Gradle 版本上启用安全 XML 处理的方法,请参阅 CVE-2023-42445 公告。
具有自定义 JEE 1.3 描述符的 EAR 插件
Gradle 8.4 禁止在解析 XML 文档时使用外部 XML 实体。如果您使用 EAR 插件并通过 EAR 插件的 DSL 配置 application.xml
描述符,并使用 withXml {}
自定义描述符,并在自定义块中使用 asElement{}
,则构建现在将因安全原因而失败。
plugins {
id("ear")
}
ear {
deploymentDescriptor {
version = "1.3"
withXml {
asElement()
}
}
}
plugins {
id("ear")
}
ear {
deploymentDescriptor {
version = "1.3"
withXml {
asElement()
}
}
}
如果您碰巧使用 asNode()
而不是 asElement()
,那么什么也不会改变,因为 asNode()
只是简单地忽略外部 DTD。
您可以通过使用设置为 http
的 javax.xml.accessExternalDTD
系统属性运行构建来解决此问题。
在命令行上,将此添加到您的 Gradle 调用中
-Djavax.xml.accessExternalDTD=http
要使此解决方法持久生效,请将以下行添加到您的 gradle.properties
systemProp.javax.xml.accessExternalDTD=http
请注意,这将为整个构建 JVM 启用对外部 DTD 的 HTTP 访问。有关更多详细信息,请参阅 JAXP 文档。
弃用
已弃用 GenerateMavenPom
方法
GenerateMavenPom
上的以下方法已被弃用,将在 Gradle 9.0 中移除。它们从未打算作为公共 API。
-
getVersionRangeMapper
-
withCompileScopeAttributes
-
withRuntimeScopeAttributes
从 8.2 及更早版本升级
潜在的破坏性更改
已弃用:Project.buildDir
可能导致脚本编译失败
随着 Project.buildDir
的弃用,如果使用了已弃用的字段,则使用将警告视为错误的编译脚本可能会失败。
有关详细信息,请参阅 弃用条目。
TestLauncher
API 不再忽略构建失败
TestLauncher
接口是 Tooling API 的一部分,专门用于运行测试。它是 BuildLauncher
的逻辑扩展,BuildLauncher
只能启动任务。已报告它们行为上的差异:如果执行相同的失败测试,BuildLauncher
将报告构建失败,但 TestLauncher
不会。最初,这是一个设计决策,目的是继续执行并运行所有测试任务中的测试,而不是在第一次失败时停止。同时,此行为可能会让用户感到困惑,因为他们可能会在成功的构建中遇到失败的测试。为了使两个 API 更加统一,我们使 TestLauncher
也导致构建失败,这是一个潜在的破坏性更改。Tooling API 客户端应显式传递 --continue
给构建,即使测试任务失败,也继续执行测试。
修复了 ArtifactView
和 ArtifactCollection
的变体选择行为
用于选择不同构件或文件的依赖项解析 API (Configuration.getIncoming().artifactView { }
和 Configuration.getIncoming().getArtifacts()
) 捕获了底层 `Configuration` 的属性的不可变副本,用于变体选择。如果在调用这些方法后更改了 `Configuration` 的属性,则这些方法选择的构件可能会出乎意料。
考虑在创建 ArtifactView
后更改 Configuration
上的一组属性的情况
tasks {
myTask {
inputFiles.from(configurations.classpath.incoming.artifactView {
attributes {
// Add attributes to select a different type of artifact
}
}.files)
}
}
configurations {
classpath {
attributes {
// Add more attributes to the configuration
}
}
}
myTask
的 inputFiles
属性使用构件视图从配置 classpath
中选择不同类型的构件。由于构件视图是在属性添加到配置之前创建的,因此 Gradle 无法选择正确的构件。
一些构建可能通过也将其他属性放入构件视图来解决此问题。现在不再需要这样做。
升级到 Kotlin 1.9.0
嵌入式 Kotlin 已从 1.8.20 更新到 Kotlin 1.9.0。Kotlin DSL 的 Kotlin 语言和 API 级别仍设置为 1.8 以实现向后兼容性。请参阅 Kotlin 1.8.22 和 Kotlin 1.8.21 的发行说明。
Kotlin 1.9 放弃了对 Kotlin 语言和 API 级别 1.3 的支持。如果您使用此版本的 Gradle 构建用 Kotlin 编写的 Gradle 插件,并且需要支持 Gradle <7.0,则需要坚持使用 Kotlin Gradle 插件 <1.9.0,并将 Kotlin 语言和 API 级别配置为 1.3。有关其他版本的详细信息,请参阅 兼容性矩阵。
Configuration
属性的急切求值
Gradle 8.3 更新了 JVM 配置的 org.gradle.libraryelements
和 org.gradle.jvm.version
属性,使其在创建时就存在,而不是像以前那样,仅在配置已解析或消费后才存在。特别是,org.gradle.jvm.version
的值依赖于项目的配置工具链,这意味着查询此属性的值将最终确定项目 Java 工具链的值。
插件或构建逻辑如果急切地查询 JVM 配置的属性,现在可能会导致项目的 Java 工具链比以前更早地最终确定。尝试在工具链最终确定后修改工具链将导致类似于以下的错误消息
The value for property 'implementation' is final and cannot be changed any further.
The value for property 'languageVersion' is final and cannot be changed any further.
The value for property 'vendor' is final and cannot be changed any further.
当插件或构建逻辑急切地查询现有 JVM 配置的属性以创建具有相同属性的新配置时,可能会出现这种情况。以前,此逻辑将完全省略上述两个属性,而现在,相同的逻辑将复制属性并最终确定项目的 Java 工具链。为了避免过早的工具链最终确定,应更新属性复制逻辑以延迟查询源配置的属性
fun <T> copyAttribute(attribute: Attribute<T>, from: AttributeContainer, to: AttributeContainer) =
to.attributeProvider<T>(attribute, provider { from.getAttribute(attribute)!! })
val source = configurations["runtimeClasspath"].attributes
configurations {
create("customRuntimeClasspath") {
source.keySet().forEach { key ->
copyAttribute(key, source, attributes)
}
}
}
def source = configurations.runtimeClasspath.attributes
configurations {
customRuntimeClasspath {
source.keySet().each { key ->
attributes.attributeProvider(key, provider { source.getAttribute(key) })
}
}
}
弃用
已弃用:Project.buildDir
将被 Project.layout.buildDirectory
替换
Project.buildDir
属性已弃用。它使用急切 API,并且如果在构建逻辑中读取该值,然后稍后修改,则会存在排序问题。这可能会导致输出最终出现在不同的位置。
它被 DirectoryProperty
替换,该属性位于 Project.layout.buildDirectory
。有关详细信息,请参阅 ProjectLayout
接口。
请注意,在此阶段,如果您仍然使用 Project.buildDir
,Gradle 不会打印弃用警告。我们知道这是一个重大更改,我们希望给主要插件的作者时间来停止使用它。
从 File
切换到 DirectoryProperty
需要在构建逻辑中进行调整。主要影响是您不能在 String
中使用该属性来扩展它。相反,您应该利用 dir
和 file
方法来计算您想要的位置。
以下是一个创建文件的示例
// Returns a java.io.File
file("$buildDir/myOutput.txt")
// Returns a java.io.File
file("$buildDir/myOutput.txt")
应替换为
// Compatible with a number of Gradle lazy APIs that accept also java.io.File
val output: Provider<RegularFile> = layout.buildDirectory.file("myOutput.txt")
// If you really need the java.io.File for a non lazy API
output.get().asFile
// Or a path for a lazy String based API
output.map { it.asFile.path }
// Compatible with a number of Gradle lazy APIs that accept also java.io.File
Provider<RegularFile> output = layout.buildDirectory.file("myOutput.txt")
// If you really need the java.io.File for a non lazy API
output.get().asFile
// Or a path for a lazy String based API
output.map { it.asFile.path }
以下是另一个创建目录的示例
// Returns a java.io.File
file("$buildDir/outputLocation")
// Returns a java.io.File
file("$buildDir/outputLocation")
应替换为
// Compatible with a number of Gradle APIs that accept a java.io.File
val output: Provider<Directory> = layout.buildDirectory.dir("outputLocation")
// If you really need the java.io.File for a non lazy API
output.get().asFile
// Or a path for a lazy String based API
output.map { it.asFile.path }
// Compatible with a number of Gradle APIs that accept a java.io.File
Provider<Directory> output = layout.buildDirectory.dir("outputLocation")
// If you really need the java.io.File for a non lazy API
output.get().asFile
// Or a path for a lazy String based API
output.map { it.asFile.path }
已弃用:声明 ClientModule
依赖项
ClientModule
依赖项已弃用,将在 Gradle 9.0 中移除。
客户端模块依赖项最初旨在允许构建通过本地定义元数据来覆盖外部依赖项的不正确或缺失的组件元数据。此功能自那时以来已被 组件元数据规则 替换。
考虑以下客户端模块依赖项示例
dependencies {
implementation(module("org:foo:1.0") {
dependency("org:bar:1.0")
module("org:baz:1.0") {
dependency("com:example:1.0")
}
})
}
dependencies {
implementation module("org:foo:1.0") {
dependency "org:bar:1.0"
module("org:baz:1.0") {
dependency "com:example:1.0"
}
}
}
可以用以下组件元数据规则替换
@CacheableRule
abstract class AddDependenciesRule @Inject constructor(val dependencies: List<String>) : ComponentMetadataRule {
override fun execute(context: ComponentMetadataContext) {
listOf("compile", "runtime").forEach { base ->
context.details.withVariant(base) {
withDependencies {
dependencies.forEach {
add(it)
}
}
}
}
}
}
dependencies {
components {
withModule<AddDependenciesRule>("org:foo") {
params(listOf(
"org:bar:1.0",
"org:baz:1.0"
))
}
withModule<AddDependenciesRule>("org:baz") {
params(listOf("com:example:1.0"))
}
}
implementation("org:foo:1.0")
}
@CacheableRule
abstract class AddDependenciesRule implements ComponentMetadataRule {
List<String> dependencies
@Inject
AddDependenciesRule(List<String> dependencies) {
this.dependencies = dependencies
}
@Override
void execute(ComponentMetadataContext context) {
["compile", "runtime"].each { base ->
context.details.withVariant(base) {
withDependencies {
dependencies.each {
add(it)
}
}
}
}
}
}
dependencies {
components {
withModule("org:foo", AddDependenciesRule) {
params([
"org:bar:1.0",
"org:baz:1.0"
])
}
withModule("org:baz", AddDependenciesRule) {
params(["com:example:1.0"])
}
}
implementation "org:foo:1.0"
}
最早支持的 Develocity 插件版本为 3.13.1
从 Gradle 9.0 开始,最早支持的 Develocity 插件版本为 3.13.1。应用时将忽略 3.0 到 3.13 的插件版本。
升级到 Develocity 插件的 3.13.1 或更高版本。您可以在 Gradle 插件门户上找到最新可用版本。有关兼容性的更多信息,请参见此处。
从 8.1 及更早版本升级
潜在的破坏性更改
升级到 Kotlin 1.8.20
嵌入式 Kotlin 已更新至 Kotlin 1.8.20。有关更多信息,请参阅 Kotlin 1.8.20 中的新增功能。
请注意,Kotlin 编译避免存在一个已知问题,如果编译类路径包含非常大的 JAR 文件,可能会导致 compileKotlin
任务中出现 OutOfMemory
异常。这适用于应用 Kotlin 插件 v1.8.20 或 kotlin-dsl
插件的构建。
您可以通过在 gradle.properties
文件中禁用 Kotlin 编译避免来解决此问题
kotlin.incremental.useClasspathSnapshot=false
有关更多信息,请参阅 KT-57757。
升级到 CodeNarc 3.2.0
CodeNarc 的默认版本已更新至 CodeNarc 3.2.0。
升级到 JaCoCo 0.8.9
JaCoCo 已更新至 0.8.9。
插件兼容性变更
使用 Gradle >= 8.2 编译的插件,如果使用了 Kotlin DSL 函数 Project.the<T>()
、Project.the(KClass)
或 Project.configure<T> {}
,则无法在 Gradle ⇐ 6.1 上运行。
某些任务的延迟或避免配置
当执行依赖项解析时,Gradle 会创建可用 Configuration 的内部表示。这需要检查所有配置和构件。处理由任务创建的构件会导致这些任务被实现和配置。
现在,这种内部表示创建得更加延迟,这可能会更改任务的配置顺序。某些任务可能永远不会被配置。
此更改可能会导致依赖于特定顺序的代码路径不再起作用,例如基于某些属性的存在有条件地向配置添加属性。
这影响了 bnd 插件和 JUnit5 构建。
我们建议不要从其他可能未配置的域对象的配置块中修改域对象(配置、源码集、任务等)。
例如,避免执行如下操作
configurations {
val myConfig = create("myConfig")
}
tasks.register("myTask") {
// This is not safe, as the execution of this block may not occur, or may not occur in the order expected
configurations["myConfig"].attributes {
attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage::class.java, Usage.JAVA_RUNTIME))
}
}
弃用
CompileOptions
方法弃用
CompileOptions
上的以下方法已被弃用
-
getAnnotationProcessorGeneratedSourcesDirectory()
-
setAnnotationProcessorGeneratedSourcesDirectory(File)
-
setAnnotationProcessorGeneratedSourcesDirectory(Provider<File>)
当前对这些方法的使用应迁移到 DirectoryProperty getGeneratedSourceOutputDirectory()
不正确地使用配置
当 Configuration 的方法与其配置的预期用途不一致地调用时,Gradle 现在会在运行时发出警告。
此更改是使配置的预期行为更一致和可预测,并解锁进一步的速度和内存改进的更大持续努力的一部分。
目前,以下方法应仅与这些列出的允许用途一起调用
-
resolve()
- 仅限 RESOLVABLE 配置 -
files(Closure)
、files(Spec)
、files(Dependency…)
、fileCollection(Spec)
、fileCollection(Closure)
、fileCollection(Dependency…)
- 仅限 RESOLVABLE 配置 -
getResolvedConfigurations()
- 仅限 RESOLVABLE 配置 -
defaultDependencies(Action)
- 仅限 DECLARABLE 配置 -
shouldResolveConsistentlyWith(Configuration)
- 仅限 RESOLVABLE 配置 -
disableConsistentResolution()
- 仅限 RESOLVABLE 配置 -
getDependencyConstraints()
- 仅限 DECLARABLE 配置 -
copy()
、copy(Spec)
、copy(Closure)
、copyRecursive()
、copyRecursive(Spec)
、copyRecursive(Closure)
- 仅限 RESOLVABLE 配置
预期用途在 Configuration
接口的 Javadoc 中注明。此列表可能会在未来的版本中增长。
从 Gradle 9.0 开始,不允许不一致地使用与其预期用途不符的配置,这将受到禁止。
另请注意,尽管目前未受到限制,但 getDependencies()
方法仅适用于 DECLARABLE 配置。getAllDependencies()
方法(检索配置及其任何超配置上的所有声明的依赖项)将不受任何特定用途的限制。
已弃用:访问插件约定
约定的概念已过时,并且已被 扩展 取代,以提供自定义 DSL。
为了在 Gradle API 中反映这一点,以下元素已被弃用
-
org.gradle.api.internal.HasConvention
Gradle Core 插件仍然注册其约定以及其扩展,以实现向后兼容性。
访问任何这些约定及其属性已被弃用。这样做现在将发出弃用警告。这将在 Gradle 9.0 中变为错误。您应该首选访问扩展及其属性。
有关具体示例,请参阅下一节。
著名的社区插件已经迁移到使用扩展来提供自定义 DSL。其中一些插件仍然注册约定以实现向后兼容性。注册约定尚不会发出弃用警告,以提供迁移窗口。未来的 Gradle 版本将会这样做。
另请注意,使用 Gradle ⇐ 8.1 编译的插件,如果使用了 Kotlin DSL 函数 Project.the<T>()
、Project.the(KClass)
或 Project.configure<T> {}
,则在 Gradle >= 8.2 上运行时将发出弃用警告。要解决此问题,应使用 Gradle >= 8.2 重新编译这些插件,或更改为直接使用 extensions.getByType<T>()
访问扩展。
已弃用:base
插件约定
base
插件贡献的约定属性已被弃用,并计划在 Gradle 9.0 中移除。有关更多上下文,请参阅 关于插件约定弃用的部分。
这些约定已由 base { }
配置块替换,该配置块由 BasePluginExtension 支持。旧的约定对象定义了具有简单 getter 和 setter 方法的 distsDirName,
libsDirName
和 archivesBaseName
属性。这些方法仅在扩展中可用,以保持向后兼容性。构建脚本应仅使用类型为 Property
的属性
plugins {
base
}
base {
archivesName.set("gradle")
distsDirectory.set(layout.buildDirectory.dir("custom-dist"))
libsDirectory.set(layout.buildDirectory.dir("custom-libs"))
}
plugins {
id 'base'
}
base {
archivesName = "gradle"
distsDirectory = layout.buildDirectory.dir('custom-dist')
libsDirectory = layout.buildDirectory.dir('custom-libs')
}
已弃用:application
插件约定
application
插件贡献的约定属性已被弃用,并计划在 Gradle 9.0 中移除。有关更多上下文,请参阅 关于插件约定弃用的部分。
以下代码现在将发出弃用警告
plugins {
application
}
applicationDefaultJvmArgs = listOf("-Dgreeting.language=en") // Accessing a convention
plugins {
id 'application'
}
applicationDefaultJvmArgs = ['-Dgreeting.language=en'] // Accessing a convention
应将其更改为使用 application { }
配置块,该配置块由 JavaApplication 支持,取而代之
plugins {
application
}
application {
applicationDefaultJvmArgs = listOf("-Dgreeting.language=en")
}
plugins {
id 'application'
}
application {
applicationDefaultJvmArgs = ['-Dgreeting.language=en']
}
已弃用:java
插件约定
java
插件贡献的约定属性已被弃用,并计划在 Gradle 9.0 中移除。有关更多上下文,请参阅 关于插件约定弃用的部分。
以下代码现在将发出弃用警告
plugins {
id("java")
}
configure<JavaPluginConvention> { // Accessing a convention
sourceCompatibility = JavaVersion.VERSION_18
}
plugins {
id 'java'
}
sourceCompatibility = 18 // Accessing a convention
应将其更改为使用 java { }
配置块,该配置块由 JavaPluginExtension 支持,取而代之
plugins {
id("java")
}
java {
sourceCompatibility = JavaVersion.VERSION_18
}
plugins {
id 'java'
}
java {
sourceCompatibility = JavaVersion.VERSION_18
}
已弃用:war
插件约定
war
插件贡献的约定属性已被弃用,并计划在 Gradle 9.0 中移除。有关更多上下文,请参阅 关于插件约定弃用的部分。
以下代码现在将发出弃用警告
plugins {
id("war")
}
configure<WarPluginConvention> { // Accessing a convention
webAppDirName = "src/main/webapp"
}
plugins {
id 'war'
}
webAppDirName = 'src/main/webapp' // Accessing a convention
客户端应直接配置 war
任务。此外,tasks.withType(War.class).configureEach(…) 可用于配置 War
类型的每个任务。
plugins {
id("war")
}
tasks.war {
webAppDirectory.set(file("src/main/webapp"))
}
plugins {
id 'war'
}
war {
webAppDirectory = file('src/main/webapp')
}
已弃用:ear
插件约定
ear
插件贡献的约定属性已被弃用,并计划在 Gradle 9.0 中移除。有关更多上下文,请参阅 关于插件约定弃用的部分。
以下代码现在将发出弃用警告
plugins {
id("ear")
}
configure<EarPluginConvention> { // Accessing a convention
appDirName = "src/main/app"
}
plugins {
id 'ear'
}
appDirName = 'src/main/app' // Accessing a convention
客户端应直接配置 ear
任务。此外,tasks.withType(Ear.class).configureEach(…) 可用于配置 Ear
类型的每个任务。
plugins {
id("ear")
}
tasks.ear {
appDirectory.set(file("src/main/app"))
}
plugins {
id 'ear'
}
ear {
appDirectory = file('src/main/app') // use application metadata found in this folder
}
已弃用:project-report
插件约定
project-reports
插件贡献的约定属性已被弃用,并计划在 Gradle 9.0 中移除。有关更多上下文,请参阅 关于插件约定弃用的部分。
以下代码现在将发出弃用警告
plugins {
`project-report`
}
configure<ProjectReportsPluginConvention> {
projectReportDirName = "custom" // Accessing a convention
}
plugins {
id 'project-report'
}
projectReportDirName = "custom" // Accessing a convention
请改为配置您的报告任务
plugins {
`project-report`
}
tasks.withType<HtmlDependencyReportTask>() {
projectReportDirectory.set(project.layout.buildDirectory.dir("reports/custom"))
}
plugins {
id 'project-report'
}
tasks.withType(HtmlDependencyReportTask) {
projectReportDirectory = project.layout.buildDirectory.dir("reports/custom")
}
依赖于自动测试框架实现依赖项
在某些情况下,Gradle 将从 Gradle 发行版加载 JVM 测试框架依赖项以执行测试。这种现有行为可能导致测试类路径上的测试框架依赖项版本冲突。为了避免这些冲突,此行为已被弃用,将在 Gradle 9.0 中移除。使用 TestNG 的测试不受影响。
为了为此行为更改做好准备,请显式声明所需的依赖项,或迁移到 测试套件,在测试套件中,这些依赖项会自动管理。
手动声明依赖项
在没有测试套件的情况下,必须在测试运行时类路径上手动声明依赖项
-
如果使用 JUnit 5,除了现有的
implementation
对测试引擎的依赖项之外,还需要显式runtimeOnly
对junit-platform-launcher
的依赖项。 -
如果使用 JUnit 4,则仅需要现有的
implementation
对junit
4 的依赖项。 -
如果使用 JUnit 3,除了
compileOnly
对junit
3 的依赖项之外,还需要测试runtimeOnly
对junit
4 的依赖项。
dependencies {
// If using JUnit Jupiter
testImplementation("org.junit.jupiter:junit-jupiter:5.9.2")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
// If using JUnit Vintage
testCompileOnly("junit:junit:4.13.2")
testRuntimeOnly("org.junit.vintage:junit-vintage-engine:5.9.2")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
// If using JUnit 4
testImplementation("junit:junit:4.13.2")
// If using JUnit 3
testCompileOnly("junit:junit:3.8.2")
testRuntimeOnly("junit:junit:4.13.2")
}
dependencies {
// If using JUnit Jupiter
testImplementation 'org.junit.jupiter:junit-jupiter:5.9.2'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
// If using JUnit Vintage
testCompileOnly 'junit:junit:4.13.2'
testRuntimeOnly 'org.junit.vintage:junit-vintage-engine:5.9.2'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
// If using JUnit 4
testImplementation 'junit:junit:4.13.2'
// If using JUnit 3
testCompileOnly 'junit:junit:3.8.2'
testRuntimeOnly 'junit:junit:4.13.2'
}
BuildIdentifier
和 ProjectComponentSelector
方法弃用
BuildIdentifier
上的以下方法已被弃用
-
getName()
-
isCurrentBuild()
您可以使用这些方法来区分来自不同构建但名称相同的不同项目组件。但是,对于某些复合构建设置,这些方法无法提供足够的信息来保证唯一性。
当前对这些方法的使用应迁移到 BuildIdentifier.getBuildPath()
。
类似地,方法 ProjectComponentSelector.getBuildName()
已被弃用。请改为使用 ProjectComponentSelector.getBuildPath()
。
从 8.0 及更早版本升级
CACHEDIR.TAG 文件在全局缓存目录中创建
Gradle 现在在某些全局缓存目录中发出 CACHEDIR.TAG
文件,如 directory_layout.html 中指定的那样。
这可能会导致某些工具不再搜索或备份这些目录。要禁用它,请在 Gradle 用户主目录的 init 脚本中使用以下代码
beforeSettings {
caches {
// Disable cache marking for all caches
markingStrategy.set(MarkingStrategy.NONE)
}
}
beforeSettings { settings ->
settings.caches {
// Disable cache marking for all caches
markingStrategy = MarkingStrategy.NONE
}
}
配置缓存选项已重命名
在此版本中,配置缓存功能已从孵化阶段提升为稳定阶段。因此,最初在功能文档中提到的所有属性(其名称中都有 unsafe
部分,例如 org.gradle.unsafe.configuration-cache
)都已重命名,在某些情况下,通过删除名称的 unsafe
部分。
孵化属性 | 最终属性 |
---|---|
|
|
|
|
|
|
请注意,此版本仍然支持原始的 org.gradle.unsafe.configuration-cache…
属性,并且如果使用它们不会产生警告,但这些属性将在未来的版本中被弃用并移除。
潜在的破坏性变更
Kotlin DSL 脚本发出编译警告
来自 Kotlin DSL 脚本的编译警告会打印到控制台输出。例如,在 Kotlin DSL 中使用已弃用的 API 每次编译脚本时都会发出警告。
如果您正在使用 Gradle 构建的控制台输出,则这是一个潜在的破坏性变更。
使用已应用的 kotlin-dsl
插件配置 Kotlin 编译器选项
如果您在应用了 kotlin-dsl 插件的项目上配置自定义 Kotlin 编译器选项,您可能会遇到破坏性变更。
在之前的 Gradle 版本中,kotlin-dsl
插件在 afterEvaluate {} 上添加必需的编译器参数。现在 Kotlin Gradle 插件提供了延迟配置属性,我们的 kotlin-dsl
插件已切换为直接将必需的编译器参数添加到延迟属性。因此,如果您设置了 freeCompilerArgs
,kotlin-dsl
插件现在会构建失败,因为其必需的编译器参数被您的配置覆盖。
plugins {
`kotlin-dsl`
}
tasks.withType(KotlinCompile::class).configureEach {
kotlinOptions { // Deprecated non-lazy configuration options
freeCompilerArgs = listOf("-Xcontext-receivers")
}
}
使用上述配置,您将收到以下构建失败
* What went wrong
Execution failed for task ':compileKotlin'.
> Kotlin compiler arguments of task ':compileKotlin' do not work for the `kotlin-dsl` plugin. The 'freeCompilerArgs' property has been reassigned. It must instead be appended to. Please use 'freeCompilerArgs.addAll(\"your\", \"args\")' to fix this.
您必须将其更改为将您的自定义编译器参数添加到 Kotlin Gradle 插件的延迟配置属性中,以便将它们附加到 kotlin-dsl
插件所需的参数之后
plugins {
`kotlin-dsl`
}
tasks.withType(KotlinCompile::class).configureEach {
compilerOptions { // New lazy configuration options
freeCompilerArgs.addAll("-Xcontext-receivers")
}
}
如果您已经添加到 freeCompilerArgs
而不是设置其值,则不应遇到构建失败。
引入的新 API 可能会与现有的 Gradle DSL 代码冲突
当向 Gradle DSL 中现有类型添加新的属性或方法时,它可能会与用户代码中已使用的名称冲突。
当发生名称冲突时,一种解决方案是重命名用户代码中的元素。
这是 8.1 中可能导致与现有用户代码名称冲突的 API 添加的不完全列表。
启用配置缓存后,不再允许在配置时使用不支持的 API 启动外部进程
自 Gradle 7.5 起,如果启用 功能预览 STABLE_CONFIGURATION_CACHE
,则在配置时使用 Project.exec
、Project.javaexec
以及标准 Java 和 Groovy API 运行外部进程才会被视为错误。随着配置缓存升级为 Gradle 8.1 中的稳定功能,无论功能预览状态如何,都会检测到此错误。配置缓存章节提供了更多详细信息,以帮助迁移到新的基于提供程序的 API,以便在配置时执行外部进程。
不使用配置缓存或仅在执行时启动外部进程的构建不受此更改的影响。
弃用
修改核心插件配置的允许用法
配置的允许用法应在创建后保持不变。修改 Gradle 核心插件创建的配置的允许用法已被弃用。这包括调用以下任何 Configuration
方法
-
setCanBeConsumed(boolean)
-
setCanBeResolved(boolean)
这些方法现在在这些配置上发出弃用警告,但某些特殊情况除外,这些情况允许流行的插件的现有行为。此规则尚不适用于分离的配置或在构建脚本和第三方插件中创建的配置。为了避免在使用某些流行的第三方插件时发出警告,在 apiElements
或 runtimeElements
上调用 setCanBeConsumed(false)
尚未弃用。
此更改是更大规模的持续努力的一部分,旨在使配置的预期行为更加一致和可预测,并在此 Gradle 领域解锁进一步的速度和内存改进。
在 Gradle 9.0 中,将移除在创建后更改配置的允许用法的能力。
保留的配置名称
配置名称 "detachedConfiguration" 和 "detachedConfigurationX"(其中 X 是任何整数)保留供内部使用,用于创建分离的配置。
在 Gradle 9.0 中,将移除使用这些名称创建非分离配置的能力。
在不存在 java
组件的情况下调用 JavaPluginExtension
上的某些方法
从 Gradle 8.1 开始,在不存在默认 java
组件的情况下,调用 JavaPluginExtension
上的以下任何方法都已被弃用
-
withJavadocJar()
-
withSourcesJar()
-
consistentResolution(Action)
此 java
组件由 JavaPlugin
添加,JavaPlugin
由任何 Gradle JVM 插件应用,包括
-
java-library
-
application
-
groovy
-
scala
从 Gradle 9.0 开始,在不存在默认 java
组件的情况下调用上述任何方法都将成为错误。
WarPlugin#configureConfiguration(ConfigurationContainer)
从 Gradle 8.1 开始,调用 WarPlugin#configureConfiguration(ConfigurationContainer)
已被弃用。此方法旨在供内部使用,从未打算用作公共接口的一部分。
从 Gradle 9.0 开始,此方法将被移除,不提供替代方法。
依赖自定义 Test 任务的约定
默认情况下,当应用 java
插件时,所有 Test
任务的 testClassesDirs
和 classpath
都具有相同的约定。除非另有更改,否则默认行为是通过使用来自 test
套件的 classpath
和 testClassesDirs
配置任务来执行默认 test
TestSuite
中的测试。此行为将在 Gradle 9.0 中移除。
虽然现有的默认行为对于在不同环境下执行默认单元测试套件的用例是正确的,但它不支持执行完全独立的测试集的使用场景。
如果您希望继续包含这些测试,请使用以下代码以避免 8.1 中的弃用警告,并为 9.0 中的行为更改做好准备。或者,考虑迁移到测试套件。
val test by testing.suites.existing(JvmTestSuite::class)
tasks.named<Test>("myTestTask") {
testClassesDirs = files(test.map { it.sources.output.classesDirs })
classpath = files(test.map { it.sources.runtimeClasspath })
}
tasks.myTestTask {
testClassesDirs = testing.suites.test.sources.output.classesDirs
classpath = testing.suites.test.sources.runtimeClasspath
}
在发布填充后修改 Gradle 模块元数据
在从组件填充 Maven 或 Ivy 发布之后,更改 GMM(例如,更改组件配置变体)现在已被弃用。此功能将在 Gradle 9.0 中移除。
如果调用以下方法,可能会发生发布的预先填充
-
Maven
-
Ivy
以前,以下代码不会生成警告,但它会在已发布的工件之间创建不一致性
publishing {
publications {
create<MavenPublication>("maven") {
from(components["java"])
}
create<IvyPublication>("ivy") {
from(components["java"])
}
}
}
// These calls eagerly populate the Maven and Ivy publications
(publishing.publications["maven"] as MavenPublication).artifacts
(publishing.publications["ivy"] as IvyPublication).artifacts
val javaComponent = components["java"] as AdhocComponentWithVariants
javaComponent.withVariantsFromConfiguration(configurations["apiElements"]) { skip() }
javaComponent.withVariantsFromConfiguration(configurations["runtimeElements"]) { skip() }
publishing {
publications {
maven(MavenPublication) {
from components.java
}
ivy(IvyPublication) {
from components.java
}
}
}
// These calls eagerly populate the Maven and Ivy publications
publishing.publications.maven.artifacts
publishing.publications.ivy.artifacts
components.java.withVariantsFromConfiguration(configurations.apiElements) { skip() }
components.java.withVariantsFromConfiguration(configurations.runtimeElements) { skip() }
在此示例中,Maven 和 Ivy 发布将包含项目的主要 JAR 工件,而 GMM 模块文件 将省略它们。
在 JVM 版本 6 和 7 上运行测试
在低于 8 的 JVM 版本上运行 JVM 测试已被弃用。在这些版本上进行测试将在 Gradle 9.0 中成为错误
应用使用 Gradle < 6.0 发布的 Kotlin DSL 预编译脚本
应用使用 Gradle < 6.0 发布的 Kotlin DSL 预编译脚本已被弃用。请使用使用 Gradle >= 6.0 发布的插件版本。
将 kotlin-dsl
与 Kotlin Gradle Plugin < 1.8.0 一起应用
将 kotlin-dsl
与 Kotlin Gradle Plugin < 1.8.0 一起应用已被弃用。请删除构建逻辑中任何显式的 kotlin-dsl
版本约束,让 Gradle 控制 kotlin-dsl
的版本。这将允许 kotlin-dsl
插件决定使用哪个版本的 Kotlin Gradle Plugin。如果您显式声明要用于构建逻辑的 Kotlin Gradle Plugin 版本,请将其更新为 >= 1.8.0。
在 Kotlin 脚本的 plugins {}
代码块中访问依赖版本目录中的 libraries
或 bundles
在 Kotlin 脚本的 plugins {}
代码块中访问依赖版本目录中的 libraries
或 bundles
已被弃用。请仅在 plugins {}
代码块中使用依赖版本目录中的 versions
或 plugins
。
在没有 Java Toolchain 的情况下使用 ValidatePlugins
任务
在没有应用 Java Toolchains 插件的情况下使用 ValidatePlugins 类型的任务已被弃用,并且将在 Gradle 9.0 中成为错误。
要避免此警告,请将该插件应用到您的项目
plugins {
id("jvm-toolchains")
}
plugins {
id 'jvm-toolchains'
}
Java Toolchains 插件由 Java library plugin 或其他 JVM 插件自动应用。因此,您可以将它们中的任何一个应用于您的项目,这将修复警告。
org.gradle.util
包中已弃用的成员现在报告其弃用
这些成员将在 Gradle 9.0 中移除。
-
WrapUtil.toDomainObjectSet(…)
-
GUtil.toCamelCase(…)
-
GUtil.toLowerCase(…)
-
ConfigureUtil
已弃用的 JVM 供应商 IBM Semeru
枚举常量 JvmVendorSpec.IBM_SEMERU
现在已被弃用,将在 Gradle 9.0 中移除。
请将其替换为其等效项 JvmVendorSpec.IBM
,以避免在下一个主要版本发布中出现警告和潜在错误。
在 StartParameter
和 GradleBuild
上设置自定义构建布局
继 Gradle 7.1 中 相关的先前弃用行为之后,现在也弃用了使用相关的 StartParameter 和 GradleBuild 属性。这些属性将在 Gradle 9.0 中移除。
在 GradleBuild 任务中,使用 buildFile 属性设置自定义构建文件已被弃用。
请改用 dir 属性来指定嵌套构建的根目录。或者,考虑使用 GradleBuild 任务的推荐替代方案之一。
使用 StartParameter 方法 setBuildFile(File) 和 setSettingsFile(File) 以及对应的 getter getBuildFile() 和 getSettingsFile() 设置自定义构建布局已被弃用。
请使用设置文件和构建文件的标准位置
-
构建根目录中的设置文件
-
每个子项目根目录中的构建文件
已弃用的 org.gradle.cache.cleanup 属性
Gradle 用户主目录下的 gradle.properties
文件中的 org.gradle.cache.cleanup
属性已被弃用。请改用 缓存清理 DSL 来禁用或修改清理配置。
由于旧版本的 Gradle 可能仍需要 org.gradle.cache.cleanup
属性,因此只要也通过 DSL 配置了此属性,该属性仍可能存在,并且不会打印弃用警告。DSL 值将始终优先于 org.gradle.cache.cleanup
属性。如果所需的配置是为旧版本的 Gradle(使用 org.gradle.cache.cleanup
)禁用清理,但为 Gradle 8 或更高版本启用具有默认值的清理,则应将清理配置为使用 Cleanup.DEFAULT
if (GradleVersion.current() >= GradleVersion.version('8.0')) {
apply from: "gradle8/cache-settings.gradle"
}
if (GradleVersion.current() >= GradleVersion.version("8.0")) {
apply(from = "gradle8/cache-settings.gradle")
}
beforeSettings { settings ->
settings.caches {
cleanup = Cleanup.DEFAULT
}
}
beforeSettings {
caches {
cleanup.set(Cleanup.DEFAULT)
}
}
已弃用使用相对路径来指定 Java 可执行文件
现在已弃用使用相对文件路径来指向 Java 可执行文件,并且将在 Gradle 9 中成为错误。这样做是为了减少关于此类相对路径应相对于什么解析的困惑。
从任务动作中调用 Task.getConvention()
、Task.getExtensions()
现在已弃用在执行时从任务动作中调用 Task.getConvention()、Task.getExtensions(),并且将在 Gradle 9.0 中使其成为错误。
有关如何将这些用法迁移到配置缓存支持的 API 的详细信息,请参阅配置缓存章节。
已弃用在未执行任何测试时成功运行测试任务
现在已弃用在未执行任何测试时成功运行 Test
任务,并且将在 Gradle 9 中成为错误。请注意,当不存在测试源时,这不是错误,在这种情况下,test
任务只是被跳过。只有当存在测试源但未选择任何测试执行时,这才是错误。更改此项是为了避免由于错误的配置而意外成功运行测试。
IDE 集成方面的变更
Kotlin DSL plugins {}
代码块中使用版本目录显示的误报错误的解决方法不再需要
用于 plugins {}
代码块中插件别名的版本目录访问器不再在 IntelliJ IDEA 和 Android Studio Kotlin 脚本编辑器中显示为错误。
如果您之前使用 @Suppress("DSL_SCOPE_VIOLATION")
注解作为解决方法,您现在可以将其删除。
如果您之前使用 Gradle Libs Error Suppressor IntelliJ IDEA 插件,您现在可以卸载它。
将 Gradle 升级到 8.1 后,您需要清除 IDE 缓存并重新启动。