You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将Closure或Gradle Action作为输入传递给自定义Gradle任务?

问题分析

  1. 类型不匹配:自定义任务中renamer声明为Property<Action<Path>>,但实际使用时传入的是(String) -> String类型的闭包,参数类型完全不兼容。
  2. 序列化失败:Action接口未继承Serializable,而@CacheableTask要求所有@Input标记的属性必须可序列化,否则任务缓存逻辑会直接报错。

解决方案

方案1:使用Gradle内置Transformer接口(推荐)

Gradle提供的Transformer<T, U>是原生支持序列化的函数式接口,完美适配“输入转换为输出”的重命名场景,且能被Gradle缓存机制正确识别。

修改自定义任务代码:

@CacheableTask
abstract class FooTask : DefaultTask() {

    @get:InputFile
    abstract val input: RegularFileProperty

    @get:Input
    abstract val renamer: Property<Transformer<String, Path>>

    @TaskAction
    fun generate() {
        val path = input.get().asFile.toPath()
        val newName = renamer.get().transform(path)
        logger.quiet("original: $path, final: $newName")
    }
}

注意:将input的@Input改为@InputFile,这是Gradle处理文件类输入的标准注解,比通用@Input更精准。

在build.gradle.kts中调用:

tasks {
    register<FooTask>("foo") {
        group = "foo"
        input.set(layout.projectDirectory.file("test.bar"))
        renamer.set { path: Path ->
            path.fileName.toString().replace(Regex("(.*)\\.bar"), "$1.baz")
        }
    }
}

方案2:自定义可序列化函数接口

如果需要完全贴合原有逻辑结构,可以自行定义继承Serializable的函数式接口:

interface SerializablePathRenamer : (Path) -> String, Serializable

@CacheableTask
abstract class FooTask : DefaultTask() {

    @get:InputFile
    abstract val input: RegularFileProperty

    @get:Input
    abstract val renamer: Property<SerializablePathRenamer>

    @TaskAction
    fun generate() {
        val path = input.get().asFile.toPath()
        val newName = renamer.get().invoke(path)
        logger.quiet("original: $path, final: $newName")
    }
}

调用时直接传递Kotlin闭包即可,Gradle会自动将其适配为可序列化的实现:

tasks {
    register<FooTask>("foo") {
        group = "foo"
        input.set(layout.projectDirectory.file("test.bar"))
        renamer.set { path ->
            path.fileName.toString().replace(Regex("(.*)\\.bar"), "$1.baz")
        }
    }
}

关于Copy任务的实现逻辑

Gradle内置的Copy任务对用户自定义闭包做了特殊处理:

  • 内部用可序列化的包装类封装用户传入的闭包
  • 计算缓存哈希时,会解析闭包的代码内容(而非仅依赖对象序列化),确保逻辑变更时能正确失效缓存

内容的提问来源于stack exchange,提问作者phreed

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 06:45:32