As of this writing there are 1,396 public types with 6,275 public methods available in Gradle’s public API to compile Java code against. Kotlin DSL and Groovy DSL each add some syntactic sugar on top of these. Some inconsistencies are bound to manifest over the years in such a large API.
One of the most significant inconsistencies is about our redundant configuration model. Historically, Gradle’s build model was configured using the JavaBeans model, i.e. properties defined via getters and setters. In 2017 we introduced the provider API as an alternative configuration model with a number of benefits, like lazy configuration, tracking build dependencies and lifecycle management on a fine-grained level.
The plan was to eventually convert the entirety of the Gradle API to the provider API, but it was never fully implemented. At present about 12% of public properties use provider API semantics. The rest is mostly exposed as JavaBean properties, but there is also a significant number of methods that conform to neither standard.
The inconsistency of our configuration model is the cause for some of the most reported problems, and the largest culprit for accidental complexity in Gradle builds. Full conversion would mean a lazy-only configuration model that would make some mistakes impossible to make that currently cause performance issues like cache misses, but can even result in incorrect builds. A lazy-only API also means we could track the origin of the value of a property, e.g. we can tell if a JavaCompile task is configured for Java 8 source compatibility because of a convention plugin, dictated by the JDK being used, or set from a build script. Some future features like coarse-grained execution, sandboxing and remote execution depend on a fully lazy API, or would be significantly simpler to implement with.
In Gradle 9.0 we are planning to migrate a large part of the remaining public API to use providers.
Looking forward to seeing how these changes shape the future of Gradle and make builds more robust and developer-friendly!
Full Comment
This Provider API migration is a crucial step toward simplifying Gradle's configuration model and enhancing build performance and reliability. Transitioning fully to a lazy-only API will mitigate accidental complexity, reduce cache misses, and lead to more predictable build outcomes. Additionally, this will allow for advanced capabilities such as tracking the source of property values, which will help developers better understand how configurations are derived.
As this migration proceeds, it would be helpful to:
Clearly document changes to public APIs for developers transitioning existing projects.
Provide detailed guidance on upgrading from JavaBeans-style properties to the Provider API, highlighting the advantages and common pitfalls.
Outline the anticipated improvements in performance and debugging when using the lazy configuration model.
NOTE: edited by @oleg-nenashev on 19.11.2024, to keep the summary expandable
As of this writing there are 1,396 public types with 6,275 public methods available in Gradle’s public API to compile Java code against. Kotlin DSL and Groovy DSL each add some syntactic sugar on top of these. Some inconsistencies are bound to manifest over the years in such a large API.
One of the most significant inconsistencies is about our redundant configuration model. Historically, Gradle’s build model was configured using the JavaBeans model, i.e. properties defined via getters and setters. In 2017 we introduced the provider API as an alternative configuration model with a number of benefits, like lazy configuration, tracking build dependencies and lifecycle management on a fine-grained level.
The plan was to eventually convert the entirety of the Gradle API to the provider API, but it was never fully implemented. At present about 12% of public properties use provider API semantics. The rest is mostly exposed as JavaBean properties, but there is also a significant number of methods that conform to neither standard.
The inconsistency of our configuration model is the cause for some of the most reported problems, and the largest culprit for accidental complexity in Gradle builds. Full conversion would mean a lazy-only configuration model that would make some mistakes impossible to make that currently cause performance issues like cache misses, but can even result in incorrect builds. A lazy-only API also means we could track the origin of the value of a property, e.g. we can tell if a
JavaCompile
task is configured for Java 8 source compatibility because of a convention plugin, dictated by the JDK being used, or set from a build script. Some future features like coarse-grained execution, sandboxing and remote execution depend on a fully lazy API, or would be significantly simpler to implement with.In Gradle 9.0 we are planning to migrate a large part of the remaining public API to use providers.
A demo of the upgrade experience can be tried here: https://github.com/gradle/provider-api-migration-testbed