使用自定义插件时 Gradle 提供的 Null 属性

Null property provided by Gradle when using custom plugin

我正在尝试按照 Gradle custom plugin documentation 创建一个可以配置的插件。

我的插件代码:

interface MyExtension {
    var myValue: Property<String>
}

class MyPlugin : Plugin<Project> {
    override fun apply(project: Project) {
        val extension = project.extensions.create<MyExtension>("myExt")
    }
}

build.gradle.kts中:

plugins {
    `java-library`
}

apply<MyPlugin>()
the<MyExtension>().myValue.set("some-value")

运行 这将给

Build file '<snip>/build.gradle.kts' line: 6
java.lang.NullPointerException (no error message)

原来 the<MyExtension>().myValuenull,因此 set 调用失败。我该如何正确地做到这一点?我是否遗漏了文档中的某些内容,或者只是错误?

文档没有错。属性可以由您或 Gradle 管理。对于后者,需要满足一定的条件。

没有托管属性

如果你想完全掌控,你可以实例化你自己声明的任何变量。例如,要在作为接口的扩展上声明 属性,它可能如下所示:

override fun apply(project: Project) {
  val extension = project.extensions.create("myExt", MyExtension::class.java)
  extension.myValue = project.objects.property(String::class.java)
}

或者您可以直接在扩展中实例化它,方法是将其设为 class:

open class MessageExtension(objects: ObjectFactory) {
  val myValue: Property<String> = objects.property(String::class.java)
}

但是,属性 字段实际上不应该具有 setter,因为 属性 本身同时具有 setter 和 getter。所以你通常应该避免第一种方法并在第二种方法中删除 setter。

有关自行管理属性的更多示例,请参阅 here

具有托管属性

为了帮助您减少样板代码,Gradle 可以使用所谓的托管属性 为您实例化属性。要使用这些,属性 必须 而不是 有一个 setter,并且 getter 应该是抽象的(它隐含在接口上) .所以你可以回到你的第一个例子并通过将 var 更改为 val:

来修复它
interface MyExtension {
    val myValue: Property<String> // val (getter only)
}

现在 Gradle 将为您实例化该字段。同样的事情适用于抽象 classes.

在文档 here 中阅读有关托管属性的更多信息。