我有以下groovy类作为我的gradle插件的一部分:
class MyClass {
final Expando someOptions
MyClass() {
someOptions = new Expando()
}
def call(Closure configure) {
configure.delegate = someOptions
configure.resolveStrategy = Closure.DELEGATE_ONLY
configure()
}
}
现在我希望用户能够通过向其添加额外属性来配置此类,但这些属性应存储在someOptions
中。
我尝试在课堂上这样做:
def call(final Closure configure) {
configure.delegate = someOptions
configure.resolveStrategy = Closure.DELEGATE_ONLY
configure()
}
插件的用户可以:
myClass {
hello='world'
}
但是,gradle似乎并不理解hello
实例上不存在myClass
属性,而是在类中的someOptions
上。每当我使用上述内容时,我都会在hello
实例中出现MyClass
错误。
我该怎么做?有可能吗?
FWIW,它在groovy控制台中工作,但不在gradle中。
答案 0 :(得分:1)
您在插件中定义的任何类都不会直接在Gradle中使用,而是由Gradle包含在代理类中。例如,
Gradle将为实际的类实现创建一个代理类,并添加(以及其他)属性setter方法。该方法具有属性的名称,并且具有与该属性相同类型的单个参数。它与Groovy已添加的
setProperty
和getProperty
方法不同。例如,如果我们的任务具有名称为String类型的消息的属性,则Gradle会将方法message(String)
添加到代理类。 (Source)
这就是为什么你可以在Gradle scrips中省略分配符号的原因:
task myTask {
myProperty true // uses Gradle generated method
myProperty = true // uses Groovy generated setter
}
Gradle还添加了一个与您类似的方法,以允许配置DSL中的任何对象:
myExtension {
// this works thanks to Gradle
}
如果没有这种代理方法,就必须使用Groovy语言中的with(Closure)
方法来处理任何块:
myExtension.with {
// this works thanks to Groovy
}
似乎此代理方法会覆盖示例的call(Closure)
方法。
要解决此问题,您可以在someOptions
上的Groovy中使用Delegate
注释。这将使MyClass
实例可以使用其所有属性。您也可以在someOptions
上注册MyClass
作为约定。
修改强>
您可以看到,在更改了call
方法的名称并明确调用它之后,通过比较当前示例和第二个堆栈跟踪的堆栈跟踪永远不会调用您的方法(您需要使用另一个属性来得到同样的例外)。