Gradle 7(Groovy 3)闭包内方法执行异常问题求助
修复Gradle 7升级后自定义插件闭包调用失败的问题
问题根源
- 错误的输入注解:
@Input注解不能用于Closure类型,Gradle 7对任务输入的验证更加严格,Closure不属于Gradle认可的可序列化输入类型,会触发配置阶段提前评估闭包。 - 闭包委托上下文错误:Gradle 7中标记为
@Input的闭包会在配置阶段被评估,此时闭包的默认委托是自定义Task实例,而filesMatching()是CopySpec的专属方法,Task实例没有该方法,因此抛出找不到方法的错误。
推荐修复方案:改用Action<CopySpec>替代Closure
Gradle官方推荐使用Action接口替代闭包进行配置,类型更安全,能彻底避免委托上下文混乱的问题。
步骤1:修改自定义插件代码
import org.gradle.api.Action import org.gradle.api.file.CopySpec import org.gradle.api.tasks.Optional import org.gradle.api.tasks.TaskAction class MyCustomTask extends DefaultTask { // 替换原Closure属性为Action<CopySpec>,默认空实现 @Optional Action<CopySpec> myCopyAction = Action.nop() private void copyFiles() { println "--------------------------Copying" project.copy { CopySpec copySpec -> from "${project.projectDir}/src/main/resources" into "${buildDir}" // 将Action直接应用到CopySpec上下文 myCopyAction.execute(copySpec) } } @TaskAction def custom() { // ... 原有业务逻辑 copyFiles() // ... 原有业务逻辑 } }
步骤2:主项目调用代码(无需修改)
Groovy会自动将闭包转换为Action实例,因此主项目代码可以保持不变:
task(type: MyCustomTask, 'custom') { myCopyAction = { filesMatching('**/my.yaml') { filter { it.replace('${test}', 'TEST') } } } // ... 其他配置 }
如果希望完全保留原属性名myClosure,只需修改插件中的属性名即可,主项目代码无需调整:
@Optional Action<CopySpec> myClosure = Action.nop()
兼容Closure的替代方案(不推荐)
如果必须保留Closure类型,需要移除@Input注解,并确保闭包仅在执行阶段评估,同时明确设置委托策略:
import org.gradle.api.tasks.Optional import org.gradle.api.tasks.TaskAction class MyCustomTask extends DefaultTask { // 移除@Input注解,避免配置阶段提前评估 @Optional Closure myClosure = { } private void copyFiles() { println "--------------------------Copying" project.copy { from "${project.projectDir}/src/main/resources" into "${buildDir}" final cl = myClosure.clone() // 设置委托策略为优先使用CopySpec的方法 cl.resolveStrategy = Closure.DELEGATE_FIRST cl.delegate = delegate cl() } } @TaskAction def custom() { // ... 原有业务逻辑 copyFiles() // ... 原有业务逻辑 } }
这种方式虽能临时解决问题,但不符合Gradle现代API设计理念,类型不安全,后续版本仍可能出现兼容性问题,因此优先推荐Action方案。
内容的提问来源于stack exchange,提问作者MKB
相关产品推荐
相关产品推荐

