Configuration Cache problem: can't get Project properties into classes

We want to make our Gradle plugin (8.1.1) compatible with Configuration Cache, so we need a way to pass some Project properties into classes.

We tried to use ProjectLayout, but that does not store properties needed by some classes, only a few of the paths can be used.

We’ve tried using a MapProperty:
abstract MapProperty<String, Object> getProperties()
But when we use any method to get a specific property in this way either with:
getProperties().getting(KEY).isPresent() or getProperties().getting(KEY).getting().get()
we get the following error
"Cannot get the value of a property of type java.util.Map with value type java.lang.Object as the source contains a null value for key <first_key_in_map>"

The Property is set in the calling class with:

Map properties = [:]
object.options.each { property ->
    properties[property] = project.findProperty(property)
}
object.properties.set(properties )

where the object is the class with the Map property, options is an array with the keys that we want in the class from the properties of Project.

When we run getProperties().keySet().get() we get no error and we get the keys successfully, but we can’t get the values of the keys.

Does anybody have an idea what is wrong / where we went wrong?

Thanks in advance,

Jos Vermeijlen.

Not all Map implementations out there support null keys,
not all Map implementations or there support null values.
Some support either the one or the other, some support both, some support none.

Similar for MapProperty.
This does neither support null keys, nor null values.

If you try to do objects.mapProperty(String, String).put(null, "") you immediately get

Cannot add an entry with a null key to a property of type Map.

If you try to do objects.mapProperty(String, String).put("", null) you immediately get

Cannot add an entry with a null value to a property of type Map.

If you try to do

objects
    .mapProperty(String, String)
    .tap { it.set([(null): ""]) }
    .get()
    .get("b")

you get

Cannot get the value of a property of type java.util.Map with key type java.lang.String as the source contains a null key.

If you try to do

objects
    .mapProperty(String, String)
    .tap { it.set(["": null]) }
    .get()
    .get("b")

you get

Cannot get the value of a property of type java.util.Map with value type java.lang.String as the source contains a null value for key “a”.

It actually also does not make much sense to build a map up-front to then set the whole map.
That is mainly for when you already have something available as map to give it in.
In your case you should just use put.
You might have used set because put die not let you pass in null values, but as you see, set lets you put them in, but when you try to use it latest, you still get an error.

So what you probably intended is:

object.options.each { property ->
    project.findProperty(property)?.with { value -> 
        object.properties.put(property, value)
    }
}

Tnx, we’ll have a look at it.

1 Like