gradle扩展能否处理属性的惰性计算?

gradle扩展能否处理属性的惰性计算?,gradle,Gradle,我正在编写一个自定义gradle插件来处理一些模糊复杂的工作,在使用属性配置插件应用的一些任务时遇到了一个令人沮丧的问题 应用插件:myPlugin //提供应用插件的属性 myPluginProps{ message=“你好” } //定义直接使用自定义任务的任务 任务thisTaskWorksFine(类型:MyTask){ 输入=myPluginProps.message } //定义一个插件,该插件将应用自定义类型的任务 类MyPlugin实现插件{ 无效申请(项目){ project.

我正在编写一个自定义gradle插件来处理一些模糊复杂的工作,在使用属性配置插件应用的一些任务时遇到了一个令人沮丧的问题

应用插件:myPlugin
//提供应用插件的属性
myPluginProps{
message=“你好”
}
//定义直接使用自定义任务的任务
任务thisTaskWorksFine(类型:MyTask){
输入=myPluginProps.message
}
//定义一个插件,该插件将应用自定义类型的任务
类MyPlugin实现插件{
无效申请(项目){
project.extensions.create('myPluginProps',MyPluginExtension)
project.task(类型:MyTask,'ThisTaskWorks'){
输入=project.myPluginProps.message
}
}
}
//我的自定义插件用于获取输入的扩展
类myplugin{
def字符串消息
}
//标准构建部分和插件使用的任务
类MyTask扩展了DefaultTask{
def字符串输入
@任务行动
def操作(){
println“你给了我这个:${input}”
}
}
使用此文件的结果如下所示:

$ gradle thisTaskWorksFine thisTaskWorksIncorrectly
:thisTaskWorksFine
You gave me this: Hello
:thisTaskWorksIncorrectly
You gave me this: null

BUILD SUCCESSFUL
我认为这是非常出乎意料的。在我看来,从插件中应用一个任务并直接编写一个任务,在给定相同的输入时,应该会得到相同的输出。在本例中,这两个任务都作为输入提供给了
myPluginProps.message
,但是插件应用的任务是贪婪的,并且在早期计算结果为null。(在应用阶段?)

我发现的唯一解决方案是在插件任务的配置块中使用闭包,如下所示:

//定义将应用自定义类型任务的插件
类MyPlugin实现插件{
无效申请(项目){
project.extensions.create('myPluginProps',MyPluginExtension)
project.task(类型:MyTask,'ThisTaskWorks'){
输入={project.myPluginProps.message}
}
}
}
这很好地解决了贪婪的评估问题,只是现在必须修改自定义任务以期望和处理闭包。这并不是很难做到,但我认为任务不应该负责处理关闭,因为插件是“罪魁祸首”

我在这里使用的扩展不正确吗?还是仅仅是不够?官方的立场似乎是这样,但我还没有找到任何扩展可以满足我需要的例子。我可以继续使用闭包,编写一系列样板getter来进行闭包求值,并编写setter来处理闭包和正常类型,但这似乎与groovy的理念背道而驰,因此也与gradle背道而驰。如果有一种方法可以使用扩展并自动获得延迟评估,我将非常高兴。

编辑

下面的答案现在已经过时了。因为我提供了一种比约定映射更好的机制,所以我们引入了一种称为


此问题的通常解决方案是使用约定映射:

classmyplugin实现插件{
无效申请(项目){
project.extensions.create('myPluginProps',MyPluginExtension)
project.task(类型:MyTask,'ThisTaskWorks'){
conventionMapping.input={project.myPluginProps.message}
}
}
}
然后在任务中:

类MyTask扩展了DefaultTask{
def字符串输入
@任务行动
def操作(){
println“你给了我这个:${getInput()}”
}
}


请注意,我明确地将getter用于
输入
——如果直接引用字段,约定映射将不会生效。

Peter在我的问题中的回答表明约定映射功能肯定会消失。最好避免

使用
afterEvaluate
来解决延迟配置问题,使我的代码比常规映射方法干净得多

classmyplugin实现插件{
无效申请(项目){
project.extensions.create('myPluginProps',MyPluginExtension)
项目后评估{
project.task(类型:MyTask,'ThisTaskWorks'){
输入=project.myPluginProps.message
}
}
}
}

约定映射和约定之间有区别吗?你的答案看起来很圆滑,所以我几乎肯定会使用它,但是一个核心开发人员说“简而言之,只使用扩展,不使用约定。”也许我把它理解得太字面了。Peter提到的是旧的扩展机制。不同之处在于,您可以通过扩展免费获得dsl(
myPluginProps{message=“Hello”}
),而不是通过约定获得它们。约定和约定映射是两种不同的东西,约定映射在内部被大量使用。非常好。在我的研究中,我回避了所有提到“惯例”一词的东西,但那是草率的。谢谢你的建议!