Property Access and Configuration Cache Question

gradle Newbie here - feel free to point me to the right RTFM, because I did not find it…

I have some properties in my gradle.properties and want to access them in my tasks in the build.gradle.kts. I also want to use the configuration cache and generall use gradle the way it is intended to.

But I also want to follow programming guidelines, like not having dublicate code.

My instinct was to have global variables and set them via findProperty once and then use the variables in the tasks. The CC does not like that.

But if I use findProperty in every task, I have dublicate code. If I would want to change the name of a property for example, I would have to edit all occurences and my programming instincts are screaming at me to use a global variable here…

The way I understand the CC also would be to read and set these variables at the configuration stage. So even that does not make sense to me.

Can someone shed some light on this for me please?

// CC not happy:
// val myConstant: String? = findProperty("dummy.myConstant") as String

tasks.register("myTask") {
    // Me not happy:
    val myConstant: String? = findProperty("dummy.myConstant") as String
    doLast {
        println("MyConstant: ${myConstant}")
    }
}

tasks.register("anotherTask") {
    // Me not happy:
    val myConstant: String? = findProperty("dummy.myConstant") as String
    doLast {
        println("Also MyConstant: ${myConstant}")
    }
}

There are multiple things to note.


Imagine the contents of the script to be the content of a class, that’s overly simplified what is happening actually, so all “local variables” like the one you commented is a field of the script class instance, functions become instance functions of the script class instance, everything else is in the body of a function.

CC is unhappy because in the doLast actions you refer to the field of the script class instance which means you need to serialize the script class instance and that is not compatible with CC.

To make it CC compatible you could copy the script class instance field to a local variable, so comment in the outcommented line and change the other two val myConstant lines to val myConstant = myConstant, then CC is happy.


val myConstant: String? = findProperty("dummy.myConstant") as String will fail if dummy.myConstant is not set, because the findProperty will return null and while your variable is String? you cast it to String first which will fail if it is null, so val myConstant: String? = findProperty("dummy.myConstant") as String? would be safer against the property not being set.


In Kotlin DSL it is imho nicer to use property delegation.
For that your property must not contain a dot though as this is not valid in a Kotlin identifier.
So instead of val myConstant: String? = findProperty("dummy.myConstant") as String? you could also write val dummyMyConstant: String? by project if the property is called dummyMyConstant instead of dummy.myConstant.


You unnecessarily read the project property at configuration time even though you only intend to use it at execution time.
This hurts the configuration cache hit rate, as the configuration cache entry cannot be reused if the value of that project property changed.
So it would be better to use providers.gradleProperty (despite its name it does not read Gradle properties but project properties), then the CC entry can be reused even if the value changes as long as you only query it at configuration time.

So better would be for example this:

val myConstant = providers.gradleProperty("dummy.myConstant")

tasks.register("myTask") {
    val myConstant = myConstant
    doLast {
        println("MyConstant: ${myConstant.orNull}")
    }
}

tasks.register("anotherTask") {
    val myConstant = myConstant
    doLast {
        println("Also MyConstant: ${myConstant.orNull}")
    }
}
1 Like

Thanks a lot for the very detailed take apart! I really appreciate it.

I had actually read about Providers instead of Properties in the docu, but with no example all my guesses did not work.

I really like the version with property delegation, but in the final example you suggest to use the providers. Do I understand it correctly that the property delegation same as reading the project properties happens at configuration time and therefore the providers are the better way to that as well?

If you only need the value at execution time and want to maximize CC hit rate, then yes. :slight_smile: