Understanding Gradle Module Metadata
Gradle Module Metadata is a format used to serialize the Gradle component model. It is similar to Apache Maven™'s POM file or Apache Ivy™ ivy.xml files. The goal of metadata files is to provide to consumers a reasonable model of what is published on a repository.
Gradle Module Metadata is a unique format aimed at improving dependency resolution by making it multi-platform and variant-aware.
In particular, Gradle Module Metadata supports:
Publication of Gradle Module Metadata will enable better dependency management for your consumers:
-
early discovery of problems by detecting incompatible modules
-
consistent selection of platform-specific dependencies
-
native dependency version alignment
-
automatically getting dependencies for specific features of your library
Gradle Module Metadata is automatically published when using the Maven Publish plugin or the Ivy Publish plugin.
The specification for Gradle Module Metadata can be found here.
Mapping with other formats
Gradle Module Metadata is automatically published on Maven or Ivy repositories. However, it doesn’t replace the pom.xml or ivy.xml files: it is published alongside those files. This is done to maximize compatibility with third-party build tools.
Gradle does its best to map Gradle-specific concepts to Maven or Ivy. When a build file uses features that can only be represented in Gradle Module Metadata, Gradle will warn you at publication time. The table below summarizes how some Gradle specific features are mapped to Maven and Ivy:
Gradle | Maven | Ivy | Description |
---|---|---|---|
|
Not published |
Gradle dependency constraints are transitive, while Maven’s dependency management block isn’t |
|
Publishes the requires version |
Published the requires version |
||
Not published |
Not published |
Component capabilities are unique to Gradle |
|
Variant artifacts are uploaded, dependencies are published as optional dependencies |
Variant artifacts are uploaded, dependencies are not published |
Feature variants are a good replacement for optional dependencies |
|
Artifacts are uploaded, dependencies are those described by the mapping |
Artifacts are uploaded, dependencies are ignored |
Custom component types are probably not consumable from Maven or Ivy in any case. They usually exist in the context of a custom ecosystem. |
Disabling metadata compatibility publication warnings
If you want to suppress warnings, you can use the following APIs to do so:
-
For Maven, see the
suppress*
methods in MavenPublication -
For Ivy, see the
suppress*
methods in IvyPublication
publications {
register<MavenPublication>("maven") {
from(components["java"])
suppressPomMetadataWarningsFor("runtimeElements")
}
}
publications {
maven(MavenPublication) {
from components.java
suppressPomMetadataWarningsFor('runtimeElements')
}
}
Interactions with other build tools
Because Gradle Module Metadata is not widely spread and because it aims at maximizing compatibility with other tools, Gradle does a couple of things:
-
Gradle Module Metadata is systematically published alongside the normal descriptor for a given repository (Maven or Ivy)
-
the
pom.xml
orivy.xml
file will contain a marker comment which tells Gradle that Gradle Module Metadata exists for this module
The goal of the marker is not for other tools to parse module metadata: it’s for Gradle users only. It explains to Gradle that a better module metadata file exists and that it should use it instead. It doesn’t mean that consumption from Maven or Ivy would be broken either, only that it works in degraded mode.
This must be seen as a performance optimization: instead of having to do 2 network requests, one to get Gradle Module Metadata, then one to get the POM/Ivy file in case of a miss, Gradle will first look at the file which is most likely to be present, then only perform a 2nd request if the module was actually published with Gradle Module Metadata. |
If you know that the modules you depend on are always published with Gradle Module Metadata, you can optimize the network calls by configuring the metadata sources for a repository:
repositories {
maven {
url = uri("http://repo.mycompany.com/repo")
metadataSources {
gradleMetadata()
}
}
}
repositories {
maven {
url = "http://repo.mycompany.com/repo"
metadataSources {
gradleMetadata()
}
}
}
Gradle Module Metadata validation
Gradle Module Metadata is validated before being published.
The following rules are enforced:
-
Variant names must be unique,
-
Each variant must have at least one attribute,
-
Two variants cannot have the exact same attributes and capabilities,
-
If there are dependencies, at least one, across all variants, must carry version information.
These rules ensure the quality of the metadata produced, and help confirm that consumption will not be problematic.
Gradle Module Metadata reproducibility
The task generating the module metadata files is currently never marked UP-TO-DATE
by Gradle due to the way it is implemented.
However, if neither build inputs nor build scripts changed, the task result is effectively up-to-date: it always produces the same output.
If users desire to have a unique module
file per build invocation, it is possible to link an identifier in the produced metadata to the build that created it.
Users can choose to enable this unique identifier in their publication
:
publishing {
publications {
create<MavenPublication>("myLibrary") {
from(components["java"])
withBuildIdentifier()
}
}
}
publishing {
publications {
myLibrary(MavenPublication) {
from components.java
withBuildIdentifier()
}
}
}
With the changes above, the generated Gradle Module Metadata file will always be different, forcing downstream tasks to consider it out-of-date.
Disabling Gradle Module Metadata publication
There are situations where you might want to disable publication of Gradle Module Metadata:
-
the repository you are uploading to rejects the metadata file (unknown format)
-
you are using Maven or Ivy specific concepts which are not properly mapped to Gradle Module Metadata
In this case, disabling the publication of Gradle Module Metadata is done simply by disabling the task which generates the metadata file:
tasks.withType<GenerateModuleMetadata> {
enabled = false
}
tasks.withType(GenerateModuleMetadata) {
enabled = false
}