Gradle Extra Properties

From NovaOrdis Knowledge Base
Revision as of 04:27, 5 October 2020 by Ovidiu (talk | contribs)
Jump to navigation Jump to search

Internal

Overview

An extra property is a property that can be declared on most model object instances available to the closure being executed. Extra properties allow defining variables that are used multiple times within the same script, such as a file that is referred from multiple locations of the build script. An extra property is equivalent to a user-defined variable.

Internally, extra properties are stored as key-value pairs in a map, associated with the model object instance. For settings.gradle, the available model objects are Settings and Gradle (ProjectDescriptor does not allow defining extra properties). Settings allows defining extra properties, but those properties cannot be easily accessed at configuration and execution phase, so the best candidate for defining extra properties during the configuration phase is Gradle.

For build.gradle, extra properties can be defined on any available object model instances. The most common object to define properties on is the project instance. The the extra properties defined on the project instance are known as project properties. Extra properties on a project are visible from its sub-projects, but not vice-versa.

Extra properties are declared using an "ext" namespace closure:

ext {
  color = 'blue'
}

An equivalent assignment is:

project.ext.color = 'blue'

A benefit of using the closure over the other syntax is that multiple assignments can be declared compactly:

ext {
  color = 'blue'
  shape = 'square'
  size = 10
}

By requiring special syntax for adding a property, Gradle can fail fast when an attempt is made to set an extra property but the property name is misspelled or the property does not exist. Note that the "ext" script block or project.ext syntax must be used only for the declaration of the property, for subsequent access the extra property can be looked up directly on the project instance: once the properties have been declared, they can be read and set like predefined properties.

project.ext.color = 'green'
project.color = 'red' // project.ext.color and project.color are equivalent after property initialization

task displayColor {
  doLast {
    println project.ext.color
    println project.color
    println color
  }
}

For the above example, ./gradlew displayColor will display "red".

Extra properties can be accessed from anywhere their owning object can be accessed. This gives them a wider scope than local variables.

Extra Properties and Multi-Project Builds

The extra properties are not available and throw an execution error if they are accessed before are defined. That is why a multi-project build that declares extra properties in sub-projects' build.gradle and attempts to use them in the root project build.gradle will fail at the configuration phase:

BUILD FAILED in 3s
...
* Where:
Build file '.../root-project/build.gradle' line: 17
 
* What went wrong:
A problem occurred evaluating root project 'root-project'.
> Could not get unknown property 'myProperty' for project ':sub-project-A' of type org.gradle.api.Project.

The error occurs even "myProperty" was declared in sub-project-A's build.gradle, because the build file was not evaluated at the time the root project file is executed. If we log build.gradle evaluation, we get something like:

exiting root project build.gradle ....
entering sub-project-A build.gradle ....
exiting sub-project-A build.gradle ....

which shows that the sub-project build script is executed after the root project build script is executed.