Groovy 覆盖默认调用方法

Groovy override default call method

我有以下 groovy class 作为我的 gradle 插件的一部分:

class MyClass {
    final Expando someOptions

    MyClass() {
        someOptions = new Expando()
    }

    def call(Closure configure) {
        configure.delegate = someOptions
        configure.resolveStrategy = Closure.DELEGATE_ONLY
        configure()
    }
}

现在我希望用户能够通过向其添加额外的属性来配置此 class,但这些属性应存储在 someOptions.

我尝试在 class 中这样做:

def call(final Closure configure) {
    configure.delegate = someOptions
    configure.resolveStrategy = Closure.DELEGATE_ONLY
    configure()
}

插件的用户可以做:

myClass {
    hello='world'
}

然而,gradle 似乎不明白 hello 属性 不存在于 myClass 实例中,而是存在于 someOptions 中class。每当我使用上述内容时,我都会收到关于 hello 不存在于 MyClass 实例中的错误。

我该怎么做?可能吗?

FWIW,它在 groovy 控制台中有效,但在 gradle.

中无效

您在插件中定义的任何 类 都不会直接在 Gradle 中使用,而是由 Gradle 包装在代理 类 中。例如,

Gradle will create a proxy class for the actual class implementation and adds (among other things) also a property setter method. The method has the name of the property and has a single argument of the same type as the property. It is different from the setProperty and getProperty methods already added by Groovy. For example if we have a task with a property with the name message of type String then Gradle will add the method message(String) to the proxy class. (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 方法的名称并显式调用它(您需要使用另一个属性 得到相同的异常)。