Gradle 8.x 内升级
本章提供了将 Gradle 8.x 构建迁移到 Gradle 8.14.3 所需的信息。要从 Gradle 7.x 迁移,请先参阅旧的迁移指南。
我们建议所有用户执行以下步骤
-
尝试运行
gradle help --scan
并查看生成的构建扫描的弃用视图。这使您可以看到适用于您构建的任何弃用警告。
或者,您可以运行
gradle help --warning-mode=all
在控制台中查看弃用,尽管它可能不会报告那么多详细信息。 -
更新您的插件。
某些插件将因 Gradle 新版本而中断,因为它们使用了已删除或更改的内部 API。上一步将通过在插件尝试使用 API 的已弃用部分时发出弃用警告来帮助您识别潜在问题。
-
运行
gradle wrapper --gradle-version 8.14.3
将项目更新到 8.14.3。 -
尝试运行项目并使用故障排除指南调试任何错误。
从 8.13 及更早版本升级
潜在的重大更改
Gradle Wrapper 现在是一个可执行 JAR
Gradle Wrapper JAR 已转换为可执行 JAR。这意味着它现在包含一个 Main-Class
属性,允许使用 -jar
选项启动它,而无需手动指定类路径和主类。
当您使用 gradle wrapper
或 ./gradlew wrapper
命令更新包装器脚本时,包装器 JAR 将自动更新以反映此更改。
Settings
默认值的更改
在 Gradle 8.10 中引入的孵化中的 Settings.getDefaults()
方法已被移除。请改用 Settings.defaults(Action<SharedModelDefaults>)
方法,该方法接受一个 lambda 表达式。
此更改允许在单个项目的上下文中解释默认值,而不是在 Settings
级别。
升级到 Guava 33.4.6
Guava 已从 32.1.2 版更新到 33.4.6 版。此版本弃用了一些核心功能,包括 Charsets
。有关完整详细信息,请参阅Guava 发行说明。
EclipseClasspath.baseSourceOutputDir
现在是一个 DirectoryProperty
孵化中的 EclipseClasspath.baseSourceOutputDir
之前被声明为 Property<File>
。它现在已正确更新为 DirectoryProperty
以反映其预期类型。
升级到 JaCoCo 0.8.13
JaCoCo 已更新到 0.8.13。
JavaExec
现在默认使用 java
扩展中的工具链
以前,JavaExec
任务使用与 Gradle 进程本身相同的 Java 版本。从 Gradle 9.0 开始,当应用 java-base
插件时,JavaExec
将默认使用 java
扩展中配置的 Java 工具链。如果需要,您可以在 JavaExec
任务配置中明确覆盖工具链。
升级到 SLF4J 2.0.17
SLF4J 已从 1.7.36 更新到 2.0.17。
弃用
使用 null
键查找属性已弃用
将 null
传递给 getAttribute(Attribute)
现在已明确弃用。
以前,这会静默返回 null
。现在,会发出弃用警告。在 AttributeContainer
中不应使用 null
键执行查找。
用于 Property 类型的 Groovy 字符串到枚举的强制转换已弃用
Groovy 支持字符串到枚举的强制转换。将 String
分配给 Property<T>
,其中 T
是枚举,现在已弃用。这将在 Gradle 10 中成为错误。
此弃用仅影响使用 Groovy DSL 编写的 Groovy 插件。
Groovydoc.getAntGroovydoc()
和 org.gradle.api.internal.tasks.AntGroovydoc
已弃用
这些内部 API 被无意中暴露,现在已弃用。它们将在 Gradle 9.0 中移除。
GradlePluginDevelopmentExtension
中已弃用方法
GradlePluginDevelopmentExtension
的构造函数及其 pluginSourceSet
方法现在已弃用。
这些方法不应直接使用,它们旨在仅由 Gradle Plugin Development 插件配置。插件开发仅支持主源集。
这些方法将在 Gradle 9.0 中移除。
IdeaModule
中已弃用集合现在发出警告
org.gradle.plugins.ide.idea.model.IdeaModule
中的 testResourcesDirs
和 testSourcesDirs
属性在 Gradle 7.6 中被标记为 @Deprecated
,但直到现在才发出警告。
Gradle 现在在使用这些属性时发出弃用警告。它们将在 Gradle 9.0 中移除。
ForkOptions.getJavaHome()
和 ForkOptions.setJavaHome()
方法不再弃用
这些方法在 Gradle 8.11 中已弃用,但由于尚未有稳定的替代品,因此不再弃用。
已弃用 StartParameter.isConfigurationCacheRequested
现在发出警告
StartParameter
中的 isConfigurationCacheRequested
属性在 Gradle 8.5 中被标记为 @Deprecated
,但直到现在才发出警告。
Gradle 现在在使用此属性时发出弃用警告。它将在 Gradle 10 中移除。
从 Gradle 8.5 开始,可以通过 BuildFeatures
服务使用 configurationCache.requested
属性获取相同的信息。
已弃用的配置用法不再弃用
从 8.0 开始,向既不可解析又不可消费的配置添加构件已弃用。此弃用过于宽泛,也捕获了某些有效用法。它已在 Gradle 8.14 中移除。
从 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
接口上的急切任务创建方法已被标记为 @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
任务的配置可以互换。
请注意,由于供应商属性的类型更改,使用 jvmVendor
属性执行 updateDaemonJvm
将导致任务失败。有关新配置选项,请参阅文档。
声明带有 is
前缀和 Boolean
类型的布尔属性
Gradle 属性名称是根据 Java Bean 规范派生而来的,但有一个例外。Gradle 将带有 Boolean
返回类型和 is
前缀的方法识别为布尔属性。这是最初从 Groovy 继承的行为。Groovy 4 更严格遵循 Java Bean 规范,并且不再支持此例外。
当 Gradle 检测到布尔属性源自带有 Boolean
返回类型和 is
前缀的方法时,它将发出弃用警告。在 Gradle 9.0 中,Groovy 4 将不再在构建脚本和 Groovy 源文件中将此识别为属性。Gradle 基于属性的行为不会改变。Gradle 仍将考虑这些属性进行最新检查。在 Gradle 10 中,这些方法将不再被视为定义 Gradle 属性。当 Boolean
属性用作输入时,这可能会导致任务行为不同。
有两种选择可以解决此问题:
-
引入一个以
get
而非is
开头的新方法,该方法具有相同的行为。旧方法不需要移除(为了保持二进制兼容性),但可能需要根据下文进行调整。-
建议弃用
is-
方法,然后在未来的主要版本中将其移除。
-
-
将属性的类型(获取和设置)更改为
boolean
。这是一个破坏性更改。
对于使用第一个选项的任务输入属性,您还应该使用 @Deprecated
和 @ReplacedBy
注解旧的 is-
方法,以确保 Gradle 不使用它。例如,此代码
class MyValue {
private final Boolean property = Boolean.TRUE;
@Input
Boolean isProperty() { return property; }
}
应替换为以下内容
class MyValue {
private final 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
接口上的急切任务创建方法已被标记为 @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 中成为错误。此方法仍可在配置时使用。
只有在未启用配置缓存时才会发出弃用警告。当启用配置缓存时,对 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 10 中移除,并且 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 daemon JVM
属性 UpdateDaemonJvm.jvmVersion
的类型现在是 Property<JavaLanguageVersion>
。
如果您在构建脚本中配置了任务,则需要替换
jvmVersion = JavaVersion.VERSION_17
为
jvmVersion = JavaLanguageVersion.of(17)
使用 CLI 选项配置 Gradle Daemon 的 JVM 版本没有影响。
名称匹配更改
名称匹配逻辑已更新,将数字视为 camelCase 名称的单词边界。以前,像 unique
这样的请求会同时匹配 uniqueA
和 unique1
。现在,此类请求将因歧义而失败。为避免问题,请使用确切的名称而不是缩短的版本。
此更改影响:
-
任务选择
-
项目选择
-
依赖报告任务中的配置选择
弃用
ForkOptions 的已弃用 JavaHome 属性
ForkOptions
类型的 JavaHome 属性已弃用,并将在 Gradle 9.0 中移除。
请使用 JVM Toolchains 或 executable 属性代替。
此弃用后来被移除,对于 Gradle 8.14 及更高版本,这些方法将不再抛出弃用警告。 |
已弃用变异构建脚本配置
从 Gradle 9.0 开始,在脚本的 buildscript 块中修改配置将导致错误。这适用于项目、设置、init 和独立脚本。
buildscript 配置块仅用于控制 buildscript 类路径解析。
考虑以下在 Settings 脚本中创建新构建脚本配置并解析它的脚本:
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 开始,手动将配置实例添加到配置容器将导致错误。配置只能通过急切或延迟工厂方法添加到容器中。分离的配置和复制的配置不应添加到容器中。
对 ConfigurationContainer 调用以下方法将被禁止:- add(Configuration) - addAll(Collection) - addLater(Provider) - addAllLater(Provider)
已弃用 ProjectDependency#getDependencyProject()
ProjectDependency#getDependencyProject()
方法已弃用,并将在 Gradle 9.0 中移除。
应避免访问其他项目的可变项目实例。
要发现所有包含在解析中的项目的详细信息,请检查完整的 ResolutionResult。项目依赖项在 DependencyResult 中公开。有关此 API 的更多详细信息,请参阅用户指南中关于程序化依赖项解析的部分。这是查找解析中使用的所有项目的唯一可靠方法。仅检查声明的 `ProjectDependency`s 可能会遗漏传递性或替换的项目依赖项。
要获取目标项目的标识,请使用新的 Isolated Projects 安全项目路径方法: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,并且不必要地依赖反射。它可以替换为直接设置映射中指定的属性。
此外,依赖于 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
任务有时可能会失败。这是由于工具链解析代码中的更改,该代码在请求编译器时强制要求编译器的存在。java-base
插件使用它创建的 JavaCompile
任务来确定在未设置 sourceCompatibility
/targetCompatibility
或 release
时的默认源和目标兼容性。随着新的强制执行,即使不需要编译(例如,在没有源的项目中),在仅提供 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 daemon 将需要 JVM 17 或更高版本。这些客户端可以配置为使用与用于运行客户端的 JVM 版本不同的 JVM 版本来运行 Gradle 构建:
-
使用Daemon JVM 标准(孵化功能)
-
设置
org.gradle.java.home
Gradle 属性 -
在 Tooling API 上使用 ConfigurableLauncher#setJavaHome 方法
或者,可以将 JAVA_HOME
环境变量设置为 JVM 17 或更高版本,这将使用相同版本的 JVM 运行客户端和守护进程。
使用--no-daemon 运行 Gradle 构建或在测试中使用 ProjectBuilder 将需要 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/9.0.0/
的守护进程日志文件使用默认 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
钩子时,请考虑这些替代方案:
-
添加依赖项:使用 DependencyFactory 并在 DependencySet 上使用
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 用户主目录中各种资源的清理和保留期,从而改进了控制和一致性。
-
现在指定
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 --scan
相同版本的 Gradle Enterprise 插件。
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)
方法及其重载变体取代。
集合属性的更改
Gradle 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 的多版本 JAR。
从 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。
JSch 的替换和升级
JSch 已被 com.github.mwiede:jsch
替换,并已从 0.1.55 更新到 0.2.16。
升级到 Eclipse JGit 5.13.3
Eclipse JGit 已从 5.7.0 更新到 5.13.3。
这包括重构 Gradle 为 SSH 操作配置 JGit 的方式,从 JSch 切换到 Apache SSHD。
升级到 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 会使用一种接受无效 URL 并错误解码其他 URL 的算法来解码提供给 Project.uri(Object)
的 CharSequence
。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
已废弃
使用 main
源集在 java
扩展上调用 registerFeature
已废弃,并且将在 Gradle 10 中改变行为。
目前,使用 main
源集调用 usingSourceSet
时创建的特性与使用任何其他源集调用 usingSourceSet
时创建的特性初始化方式不同。以前,当使用 main
源集时,会创建新的 implementation
、compileOnly
、runtimeOnly
、api
和 compileOnlyApi
配置,并且 main
源集的编译和运行时类路径会配置为扩展这些配置。
从 Gradle 10 开始,main
源集将像任何其他源集一样处理。如果应用了 java-library
插件(或任何其他应用 java
插件的插件),使用 main
源集调用 usingSourceSet
将抛出异常。这是因为 java
插件已经配置了一个 main
特性。只有在没有应用 java
插件的情况下,才允许在调用 usingSourceSet
时使用 main
源集。
目前使用 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 10 开始,在观察到依赖项后修改来自 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
版本约束来避免迭代和修改。这允许依赖项管理引擎在没有声明其他版本时使用约束上声明的版本。
考虑以下示例,它用一个不加区别的 首选 版本约束替换了上面的迭代
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 中使用的 XML 解析器以兼容 Gradle 8.4。
如果无法升级来自构建逻辑依赖项的 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。
您可以通过将 javax.xml.accessExternalDTD
系统属性设置为 http
来运行构建以解决此问题。
在命令行中,将其添加到您的 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
将报告构建失败,但 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 Plugin < 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,并且如果值在构建逻辑中读取后又被修改,则存在排序问题。这可能导致输出最终位于不同的位置。
它被 Project.layout.buildDirectory
处的 DirectoryProperty
替换。有关详细信息,请参阅 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 中移除。
Client 模块依赖项最初旨在允许构建通过本地定义元数据来覆盖外部依赖项的错误或缺失组件元数据。此功能已被 组件元数据规则 替换。
考虑以下客户端模块依赖项示例
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。
插件兼容性更改
使用 Kotlin DSL 函数 Project.the<T>()
、Project.the(KClass)
或 Project.configure<T> {}
的 Gradle >= 8.2 编译的插件无法在 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()
错误使用配置
Gradle 现在将在运行时警告,当调用 Configuration 的方法与配置的预期用法不一致时。
此更改是正在进行的更大努力的一部分,旨在使配置的预期行为更加一致和可预测,并在此领域中实现进一步的速度和内存改进。
目前,以下方法只能与这些列出的允许用法一起调用
-
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.Project.getConvention()
-
org.gradle.api.plugins.Convention
-
org.gradle.api.internal.HasConvention
Gradle 核心插件除了扩展之外,仍然注册其约定以实现向后兼容性。
访问任何这些约定及其属性已被废弃。这样做现在将发出废弃警告。在 Gradle 9.0 中,这将成为错误。您应该优先访问扩展及其属性。
具体示例请参见下一节。
著名的社区插件已迁移到使用扩展来提供自定义 DSL。其中一些为了向后兼容性仍然注册约定。注册约定目前不会发出废弃警告,以提供迁移窗口。未来的 Gradle 版本将发出警告。
另请注意,使用 Kotlin DSL 函数 Project.the<T>()
、Project.the(KClass)
或 Project.configure<T> {}
的 Gradle ⇐ 8.1 编译的插件在 Gradle >= 8.2 上运行时将发出废弃警告。要修复此问题,这些插件应使用 Gradle >= 8.2 重新编译,或更改为直接使用 extensions.getByType<T>()
访问扩展。
废弃的 base
插件惯例
base
插件贡献的惯例属性已被废弃,并计划在 Gradle 9.0 中移除。有关更多背景信息,请参阅关于插件惯例废弃的章节。
这些惯例被 base { }
配置块替换,该配置块由 BasePluginExtension 支持。旧的惯例对象定义了 distsDirName
、libsDirName
和 archivesBaseName
属性,并带有简单的 getter 和 setter 方法。这些方法仅在扩展中可用以保持向后兼容性。构建脚本应仅使用 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
依赖项之外,还需要对junit-platform-launcher
显式指定runtimeOnly
依赖项。 -
如果使用 JUnit 4,则只需要对 JUnit 4 现有
implementation
依赖项。 -
如果使用 JUnit 3,除了对 JUnit 3 的
compileOnly
依赖项之外,还需要对 JUnit 4 的测试runtimeOnly
依赖项。
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 User Home 的 初始化脚本 中使用以下代码
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 起,在配置时使用 Project.exec
、Project.javaexec
以及标准 Java 和 Groovy API 运行外部进程仅在启用功能预览 STABLE_CONFIGURATION_CACHE
时才被视为错误。随着配置缓存提升为 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
添加,该插件由任何 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 一起应用已废弃。请让 Gradle 控制 kotlin-dsl
的版本,方法是从构建逻辑中移除任何显式 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 工具链的情况下使用 ValidatePlugins
任务
在没有应用 Java Toolchains 插件(或任何其他应用 Java Toolchains 插件的 Java 插件)的情况下使用 ValidatePlugins
类型的任务在 Gradle 8.1 中已废弃,现在在 Gradle 9.0 中是错误。
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 来禁用或修改清理配置。
由于 org.gradle.cache.cleanup
属性对于旧版本的 Gradle 可能仍然需要,因此此属性可能仍然存在,并且只要也通过 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 10 中成为错误。这样做是为了减少关于此类相对路径应解析为何的混淆。
从任务操作中调用 Task.getConvention()
, Task.getExtensions()
在执行时从任务操作中调用 Task.getConvention()
、Task.getExtensions() 现在已废弃,并将在 Gradle 9.0 中成为错误。
有关如何将这些用法迁移到配置缓存支持的 API 的详细信息,请参阅配置缓存章节。
废弃的在没有执行测试时成功运行测试任务
在没有执行测试时成功运行 Test
任务现在已废弃,并将在 Gradle 9 中成为错误。请注意,当没有测试源时,这不是错误,在这种情况下,test
任务只是被跳过。只有当存在测试源但没有选择测试执行时,它才是一个错误。此更改是为了避免由于错误配置而导致意外的成功测试运行。
IDE 集成中的更改
Kotlin DSL plugins {}
块中使用版本目录时显示错误的工作区不再需要
在 IntelliJ IDEA 和 Android Studio Kotlin 脚本编辑器中,plugins {}
块中插件别名的版本目录访问器不再显示为错误。
如果您之前使用 @Suppress("DSL_SCOPE_VIOLATION")
注解作为解决方法,现在可以将其移除。
如果您之前使用 Gradle Libs Error Suppressor IntelliJ IDEA 插件,现在可以将其卸载。
升级 Gradle 到 8.1 后,您需要清除 IDE 缓存并重新启动。