Home > Blockchain >  Null property provided by Gradle when using custom plugin
Null property provided by Gradle when using custom plugin

Time:11-23

I'm trying to follow the Gradle custom plugin documentation to create a plugin that can be configured.

My plugin code:

interface MyExtension {
    var myValue: Property<String>
}

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

in build.gradle.kts:

plugins {
    `java-library`
}

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

Running this will give

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

Turns out the the<MyExtension>().myValue is null, so the set call fails. How do I do this correctly? Did I miss something in the documentation, or is it just wrong?

CodePudding user response:

The documentation is not wrong. Properties can be managed by either you or by Gradle. For the latter, certain conditions have to be met.

Without managed properties

If you want to be completely in charge, you can instantiate any variables you declare yourself. For example, to declare a property on an extension that is an interface, it could look like this:

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

Or you could instantiate it directly in the extension by making it a class instead:

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

However, a property field is not really supposed to have a setter as the property itself has both a setter and a getter. So you should generally avoid the first approach and remove the setter on the second.

See here for more examples on managing the properties yourself.

With managed properties

To help you reduce boilerplate code, Gradle can instantiate the properties for you with what is called managed properties. To do use these, the property must not have a setter, and the getter should be abstract (which it implicitly is on an interface). So you could go back to your first example and fix it by changing var to val:

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

Now Gradle will instantiate the field for you. The same thing works for abstract classes.

Read more about managed properties in the documentation here.

  • Related