// Copyright (C) 2024 Gradle, Inc.
//
// Licensed under the Creative Commons Attribution-Noncommercial-ShareAlike 4.0 International License.;
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      https://creativecommons.org/licenses/by-nc-sa/4.0/
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

:metadata-file-spec: https://github.com/gradle/gradle/blob/master/platforms/documentation/docs/src/docs/design/gradle-module-metadata-latest-specification.md

[[understanding_dependency_resolution_model]]
= Understanding the Dependency Resolution Model

This chapter explains how dependency resolution works within Gradle.
After learning how to declare <<declaring_repositories.adoc#three-declaring-repositories,repositories>> and <<declaring_dependencies.adoc#one-declaring-dependencies,dependencies>>, the next step is understanding how these declarations are combined during the dependency resolution process.

Dependency resolution happens in two key phases, repeated until the entire dependency graph is constructed:

1. **Conflict Resolution**: When a new dependency is introduced, Gradle resolves any conflicts to determine the version that should be added to the graph.
2. **Dependency Metadata Retrieval**: Once a specific dependency (a module with a version) is included in the graph, Gradle retrieves its metadata, adding its own dependencies to the graph in turn.

This process continues until the entire dependency tree is resolved.

[[sec:conflict-resolution]]
== Phase 1. Conflict resolution

When performing dependency resolution, Gradle handles two types of conflicts:

A. **Version conflicts**: Occur when multiple dependencies request the same dependency but with different versions. Gradle must choose which version to include in the graph.
B. **Implementation / Capability conflicts**: Occur when the dependency graph contains different modules that provide the same functionality or _capability_. Gradle resolves these by selecting one module to avoid duplicate implementations.

The dependency resolution process is highly customizable and many APIs can influence the process.

[[sec:version-conflict]]
=== A. Version conflicts

A version conflict occurs when two components:

* Depend on the same module, such as `com.google.guava:guava`
* But on different versions, for example, `20.0` and `25.1-android`:
** Our project directly depends on `com.google.guava:guava:20.0`
** Our project also depends on `com.google.inject:guice:4.2.2`, which in turn depends on `com.google.guava:guava:25.1-android`

[[sec:resolution-strategy]]
Gradle must resolve this conflict by selecting one version to include in the dependency graph.

Gradle considers all requested versions across the dependency graph and, by default, selects the _highest_ version.
Detailed version ordering is explained in <<dependency_versions.adoc#sec:version-ordering,version ordering>>.

Gradle also supports the concept of <<dependency_versions.adoc#sec:rich-version-constraints,rich version declarations>>, which means that what constitutes the "highest" version depends on how the versions were declared:

* **Without ranges**: The highest non-rejected version will be selected.
** If a `strictly` version is declared that is lower than the highest, resolution will fail.
* **With ranges**:
** If a non-range version fits within the range or is higher than the upper bound, it will be selected.
** If only ranges exist, the selection depends on the intersection of those ranges:
*** If ranges overlap, the highest _existing_ version in the intersection is selected.
*** If no clear intersection exists, the highest version from the largest range will be selected. If no version exists in the highest range, the resolution fails.
** If a `strictly` version is declared that is lower than the highest, resolution will fail.

For version ranges, Gradle needs to perform intermediate metadata lookups to determine which versions are available, as explained in <<#sec:how-gradle-downloads-deps>>.

[[sec:base-version-comparison]]
==== Versions with qualifiers

The term "qualifier" refers to the portion of a version string that comes after a non-dot separator, like a hyphen or underscore.

For example:

[cols="1,1,1"]
|===
|Original version | Base version | Qualifier

|1.2.3
|1.2.3
|<none>

|1.2-3
|1.2
|3

|1_alpha
|1
|alpha

|abc
|abc
|<none>

|1.2b3
|1.2
|b3

|abc.1+3
|abc.1
|3

|b1-2-3.3
|b
|1-2-3.3
|===

As you can see separators are any of the `.`, `-`, `_`, `+` characters, plus the empty string when a numeric and a non-numeric part of the version are next to each-other.

Gradle gives preference to versions without qualifiers when resolving conflicts.

For example, in version `1.0-beta`, the base form is `1.0`, and `beta` is the qualifier.
Versions without qualifiers are considered more stable, so Gradle will prioritize them.

Here are a few examples to clarify:

- `1.0.0` (no qualifier)
- `1.0.0-beta` (qualifier: `beta`)
- `2.1-rc1` (qualifier: `rc1`)

Even if the qualifier is lexicographically higher, Gradle will typically consider a version like `1.0.0` higher than `1.0.0-beta`.

When resolving conflicts between versions, Gradle applies the following logic:

1. **Base version comparison:** Gradle first selects versions with the highest base version, ignoring any qualifiers.
All others are discarded.
2. **Qualifier handling:** If there are still multiple versions with the same base version, Gradle picks one with a preference for versions without qualifiers (i.e., release versions).
If all versions have qualifiers, Gradle will consider the qualifier's order, preferring more stable ones like "release" over others such as "beta" or "alpha."

[[sec:implementation-conflict]]
=== B. Implementation / Capability conflicts

Gradle uses **variants** and **capabilities** to define what a module *provides*.

<<component_capabilities.adoc#sec:selecting-between-candidates,Conflicts>> arise in the following scenarios:

- **Incompatible variants**: When two modules attempt to select different, incompatible variants of a dependency.
- **Same capability**: When multiple modules declare the same capability, creating an overlap in functionality.

For more details on how variant selection works and how it enables flexible dependency management, refer to the <<variant_model.adoc#sec:understanding-variant-selection>> below.

[[sec:how-gradle-downloads-deps]]
== Phase 2. Dependency metadata retrieval

Gradle requires module metadata in the dependency graph for two reasons:

A. **Determining existing versions for dynamic dependencies**: When a dynamic version (like `1.+` or `latest.release`) is specified, Gradle must identify the concrete versions available.

B. **Resolving module dependencies for a specific version**: Gradle retrieves the dependencies associated with a module based on the specified version, ensuring the correct transitive dependencies are included in the build.

=== A. Determining existing versions for dynamic dependencies

When faced with a dynamic version, Gradle must identify the available concrete versions through the following steps:

1. **Inspecting repositories**: Gradle checks each defined repository in the order they were added. It doesn't stop at the first one that returns metadata but continues through all available repositories.

2. **Maven repositories**: Gradle retrieves version information from the `maven-metadata.xml` file, which lists available versions.

3. **Ivy repositories**: Gradle resorts to a directory listing to gather available versions.

The result is a list of candidate versions that Gradle evaluates and matches to the dynamic version.
Gradle <<dependency_caching.adoc#sec:controlling-dynamic-version-caching,caches>> this information to optimize future resolution.
At this point, <<#sec:resolution-strategy,version conflict resolution>> is resumed.

=== B. Resolving module dependencies for a specific version

When Gradle tries to resolve a required dependency with a specific version, it follows this process:

1. **Repository inspection**: Gradle checks each repository in the order they are defined.
- It looks for metadata files describing the module (`.module`, `.pom`, or `ivy.xml`), or directly for artifact files.
- Modules with metadata files (`.module`, `.pom`, or `ivy.xml`) are prioritized over those with just an artifact file.
- Once metadata is found in a repository, subsequent repositories are ignored.
2. **Retrieving and parsing metadata**: If metadata is found, it is parsed.
- If the POM file has a parent POM, Gradle recursively resolves each parent module.
3. **Requesting artifacts**: All artifacts for the module are fetched from the same repository that provided the metadata.
4. **Caching**: All data, including the repository source and any potential misses, are stored in the <<dependency_caching.adoc#sec:controlling-dynamic-version-caching,dependency cache>> for future use.

[NOTE]
====
The point above highlights a potential issue with integrating <<supported_repository_types.adoc#sec:case-for-maven-local,Maven Local>>. Since Maven Local acts as a Maven cache, it may occasionally miss artifacts for a module. When Gradle sources a module from Maven Local and artifacts are missing, it assumes those artifacts are entirely unavailable.
====

[[sec:repository-disabling]]
== Repository disabling

When Gradle fails to retrieve information from a repository, it disables the repository for the remainder of the build and fails all dependency resolution.

This behavior ensures reproducibility.

If the build were to continue while ignoring the faulty repository, subsequent builds could produce different results once the repository is back online.

[[sub:http-retries]]
=== HTTP Retries

Gradle will attempt to connect to a repository multiple times before disabling it.
If the connection fails, Gradle retries on specific errors that might be temporary, with increasing wait times between retries.

A repository is blacklisted when it cannot be reached, either due to a permanent error or after the maximum number of retries has been exhausted.

[[sec:understanding-variant-selection]]
== Understanding variant selection

Gradle's dependency management engine is _variant aware_.

image::component-model-gradle.png[]

In addition to components, Gradle introduces the concept of _variants_.
Variants represent different ways a component can be used, such as for Java compilation, native linking, or documentation.
Each variant may have its own artifacts and dependencies.

When multiple variants are available, Gradle uses <<variant_attributes.adoc#variant-attributes,attributes>> to determine which variant to choose.
These attributes provide meaning to the variants and ensure that the dependency resolution process produces a consistent result.

Here are some examples of common variants in Gradle:

1. **Java Component Variants**:
- **`compile`**: Used for compiling Java code, with dependencies needed at compile-time.
- **`runtime`**: Used for running the application, with dependencies needed at runtime.

2. **Android Build Variants**:
- **`debug`**: A variant used for development, with debug symbols and test configurations enabled.
- **`release`**: A production-ready variant with optimizations, obfuscation, and without debugging tools.
- **`flavors`**: Variants that represent different product flavors, such as `freeDebug`, `paidRelease`, etc.

Gradle distinguishes between two types of components:

- Local components (like projects), which are built from sources such as `:json-library`
- External components, which are published to repositories such as `org.apache.commons:commons-lang3:3.12.0`

For local components, <<#sec:abm-configuration-attributes, variants are mapped to consumable configurations>>.
For external components, variants are defined by Gradle Module Metadata or <<#sec:mapping-maven-ivy-to-variants, derived from Ivy/Maven metadata>>.

.Variants vs Configurations
--
Variants and configurations are sometimes used interchangeably in Gradle's documentation, DSLs, or APIs due to historical reasons.

All components provide variants, and these variants may be backed by a consumable configuration.
However, not all configurations are variants, as some are used solely for declaring or resolving dependencies rather than representing consumable component variants.
--

[[sec:abm-configuration-attributes]]
=== Variant attributes

<<variant_attributes.adoc#variant-attributes,Attributes>> are type-safe key-value pairs used by both the consumer and the producer during variant selection.

- **Consumer attributes**: Define the desired characteristics of a variant for a resolvable configuration.
The consumer can specify multiple attributes to narrow down the available options.
- **Producer attributes**: Each variant can have a set of attributes that describe its purpose.
For example, the `org.gradle.usage` attribute specifies whether the variant is meant for compilation, runtime execution, or other uses.
Not all attributes of a variant need to match the consumer's specified attributes for selection.

[[sec:variant-aware-matching]]
=== Variant attribute matching

IMPORTANT: The variant name is primarily used for debugging and error messages. It does not play a role in variant matching; only the variant's attributes are used in the matching process.

[[sec:abm-algorithm]]
There are no restrictions on how many variants a component can define.
A typical component will include at least an implementation variant but may also provide additional variants, such as test fixtures, documentation, or source code.
Furthermore, a component can offer _different variants_ for the same usage, depending on the consumer.
For instance, during compilation, a component may provide different headers for Linux, Windows, and macOS.

Gradle performs _variant-aware selection_ by matching the attributes specified by the consumer with those defined by the producer.
The details of this process are covered in the <<variant_model.adoc#sec:abm-algorithm, selection algorithm>> section.

[NOTE]
====
There are two exceptions to the variant-aware resolution process:

- When a producer has no variants, a default artifact is selected.
- When a consumer _explicitly selects a configuration by name_, the artifacts associated with that configuration are used.
====

=== A simple example

Let’s walk through an example where a consumer is trying to use a library for compilation.

First, the consumer details how it's going to use the result of dependency resolution.
This is achieved by setting _attributes_ on the consumer's resolvable configuration.

In this case, the consumer wants to resolve a variant that matches `org.gradle.usage=java-api`.

Next, the producer exposes different variants of its component:

- **API variant** (named `apiElements`) with the attribute `org.gradle.usage=java-api`
- **Runtime variant** (named `runtimeElements`) with the attribute `org.gradle.usage=java-runtime`

Finally, Gradle evaluates the variants and selects the correct one:

- The consumer requests a variant with attributes `org.gradle.usage=java-api`
- The producer’s `apiElements` variant matches this request.
- The producer’s `runtimeElements` variant does not match.

As a result, Gradle selects the `apiElements` variant and provides its artifacts and dependencies to the consumer.

=== A complicated example

In real-world scenarios, both consumers and producers often work with multiple attributes.

For instance, a Java Library project in Gradle will involve several attributes:

- `org.gradle.usage` describes how the variant is used.
- `org.gradle.dependency.bundling` describes how the variant handles dependencies (e.g., shadow jar, fat jar, regular jar).
- `org.gradle.libraryelements` describes the packaging of the variant (e.g., classes or jar).
- `org.gradle.jvm.version` describes the _minimal version_ of Java the variant targets.
- `org.gradle.jvm.environment` describes the type of JVM the variant targets.

Let’s consider a scenario where the consumer wants to run tests using a library on Java 8, and the producer supports two versions: Java 8 and Java 11.

**Step 1: Consumer specifies the requirements.**

The consumer wants to resolve a variant that:

- Can be used at runtime (`org.gradle.usage=java-runtime`).
- Can run on _at least_ Java 8 (`org.gradle.jvm.version=8`).

**Step 2: Producer exposes multiple variants.**

The producer offers variants for both Java 8 and Java 11 for both API and runtime usage:

- **API variant for Java 8** (named `apiJava8Elements`) with attributes `org.gradle.usage=java-api` and `org.gradle.jvm.version=8`.
- **Runtime variant for Java 8** (named `runtime8Elements`) with attributes `org.gradle.usage=java-runtime` and `org.gradle.jvm.version=8`.
- **API variant for Java 11** (named `apiJava11Elements`) with attributes `org.gradle.usage=java-api` and `org.gradle.jvm.version=11`.
- **Runtime variant for Java 11** (named `runtime11Elements`) with attributes `org.gradle.usage=java-runtime` and `org.gradle.jvm.version=11`.

**Step 3: Gradle matches the attributes.**

Gradle compares the consumer's requested attributes with the producer's variants:

- The consumer requests a variant with `org.gradle.usage=java-runtime` and `org.gradle.jvm.version=8`.
- Both `runtime8Elements` and `runtime11Elements` match the `org.gradle.usage=java-runtime` attribute.
- The API variants (`apiJava8Elements` and `apiJava11Elements`) are discarded as they don't match `org.gradle.usage=java-runtime`.
- The variant `runtime8Elements` is selected because it is compatible with Java 8.
- The variant `runtime11Elements` is incompatible because it requires Java 11.

Gradle selects `runtime8Elements` and provides its artifacts and dependencies to the consumer.

--
What happens if the consumer sets `org.gradle.jvm.version=7`?

In this case, dependency resolution would _fail_, with an error explaining there is no suitable variant.
Gradle knows the consumer requires a Java 7-compatible library, but the producer's minimum version is 8.

If the consumer requested `org.gradle.jvm.version=15`, Gradle could choose either the Java 8 or Java 11 variant. Gradle would then select the highest compatible version—Java 11.
--

[[sec:variant-select-errors]]
=== Variant selection errors

When Gradle attempts to select the most compatible variant of a component, resolution may fail due to:

- **Ambiguity error**: When more than one variant from the producer matches the consumer’s attributes, leading to confusion over which to select.
- **Incompatibility error**: When none of the producer’s variants match the consumer’s attributes, causing the resolution to fail.

[[sub:variant-ambiguity]]
=== Dealing with ambiguity errors

An ambiguous variant selection looks like this:

[source,text]
----
> Could not resolve all files for configuration ':compileClasspath'.
   > Could not resolve project :lib.
     Required by:
         project :ui
      > Cannot choose between the following variants of project :lib:
          - feature1ApiElements
          - feature2ApiElements
        All of them match the consumer attributes:
          - Variant 'feature1ApiElements' capability org.test:test-capability:1.0:
              - Unmatched attribute:
                  - Found org.gradle.category 'library' but wasn't required.
              - Compatible attributes:
                  - Provides org.gradle.dependency.bundling 'external'
                  - Provides org.gradle.jvm.version '11'
                  - Required org.gradle.libraryelements 'classes' and found value 'jar'.
                  - Provides org.gradle.usage 'java-api'
          - Variant 'feature2ApiElements' capability org.test:test-capability:1.0:
              - Unmatched attribute:
                  - Found org.gradle.category 'library' but wasn't required.
              - Compatible attributes:
                  - Provides org.gradle.dependency.bundling 'external'
                  - Provides org.gradle.jvm.version '11'
                  - Required org.gradle.libraryelements 'classes' and found value 'jar'.
                  - Provides org.gradle.usage 'java-api'
----

In this scenario, all _compatible_ candidate variants are listed along with their attributes:

- **Unmatched attributes**: Shown first, these indicate what attributes may be missing or misaligned for selecting the proper variant.
- **Compatible attributes**: Shown next, these highlight how the candidate variants align with the consumer’s requirements.
- **Incompatible attributes**: Will not be shown, as incompatible variants are excluded.

In the example above, the issue isn't with attribute matching but with <<component_capabilities.adoc#sec:selecting-between-candidates,**capability matching**>>.
Both `feature1ApiElements` and `feature2ApiElements` offer the same attributes and capabilities, making them indistinguishable to Gradle.

To resolve this, you can modify the producer (`project :lib`) to provide different capabilities or express a capability choice on the consumer side (`project :ui`) to disambiguate between the variants.

[[sec:variant-no-match]]
=== Dealing with no matching variant errors

A no matching variant error might look like this:

[source,text]
----
> No variants of project :lib match the consumer attributes:
  - Configuration ':lib:compile':
      - Incompatible attribute:
          - Required artifactType 'dll' and found incompatible value 'jar'.
      - Other compatible attribute:
          - Provides usage 'api'
  - Configuration ':lib:compile' variant debug:
      - Incompatible attribute:
          - Required artifactType 'dll' and found incompatible value 'jar'.
      - Other compatible attributes:
          - Found buildType 'debug' but wasn't required.
          - Provides usage 'api'
  - Configuration ':lib:compile' variant release:
      - Incompatible attribute:
          - Required artifactType 'dll' and found incompatible value 'jar'.
      - Other compatible attributes:
          - Found buildType 'release' but wasn't required.
          - Provides usage 'api'
----

Or:

[source,text]
----
> No variants of project : match the consumer attributes:
   - Configuration ':myElements' declares attribute 'color' with value 'blue':
       - Incompatible because this component declares attribute 'artifactType' with value 'jar' and the consumer needed attribute 'artifactType' with value 'dll'
   - Configuration ':myElements' variant secondary declares attribute 'color' with value 'blue':
       - Incompatible because this component declares attribute 'artifactType' with value 'jar' and the consumer needed attribute 'artifactType' with value 'dll'
----

In these cases, _potentially compatible_ candidate variants are displayed, showing:

- **Incompatible attributes**: Listed first to help identify why a variant could not be selected.
- **Other attributes**: Including requested and compatible attributes, and any extra producer attributes that the consumer did not request.

The goal here is to understand which variant could be selected, if any.
In some cases, there may simply be no compatible variants from the producer (for example, if the consumer requires a `dll` but the producer only offers a `jar` or if a library is built for Java 11, but the consumer requires Java 8).

[[sec:variant-incompatible]]
=== Dealing with incompatible variant errors

An incompatible variant error looks like the following example, where a consumer wants to select a variant with `color=green`, but the only variant available has `color=blue`:

[listing]
----
> Could not resolve all dependencies for configuration ':resolveMe'.
   > Could not resolve project :.
     Required by:
         project :
      > Configuration 'mismatch' in project : does not match the consumer attributes
        Configuration 'mismatch':
          - Incompatible because this component declares attribute 'color' with value 'blue' and the consumer needed attribute 'color' with value 'green'
----

It occurs when Gradle cannot select a single variant of a dependency because an explicitly requested attribute value does not match (and is not compatible with) the value of that attribute on any of the variants of the dependency.

A sub-type of this failure occurs when Gradle *successfully* selects multiple variants of the same component, but the selected variants are incompatible with *each other*.

This looks like the following, where a consumer wants to select two different variants of a component, each supplying different capabilities, which is acceptable.
Unfortunately one variant has `color=blue` and the other has `color=green`:

[listing]
----
> Could not resolve all dependencies for configuration ':resolveMe'.
   > Could not resolve project :.
     Required by:
         project :
      > Multiple incompatible variants of org.example:nyvu:1.0 were selected:
           - Variant org.example:nyvu:1.0 variant blueElementsCapability1 has attributes {color=blue}
           - Variant org.example:nyvu:1.0 variant greenElementsCapability2 has attributes {color=green}

   > Could not resolve project :.
     Required by:
         project :
      > Multiple incompatible variants of org.example:pi2e5:1.0 were selected:
           - Variant org.example:pi2e5:1.0 variant blueElementsCapability1 has attributes {color=blue}
           - Variant org.example:pi2e5:1.0 variant greenElementsCapability2 has attributes {color=green}
----

[[sec:transform-ambiguity]]
=== Dealing with ambiguous transformation errors

ArtifactTransforms can be used to transform artifacts from one type to another, changing their attributes.
Variant selection can use the attributes available as the result of an artifact transform as a candidate variant.

If a project registers multiple artifact transforms, needs to use an artifact transform to produce a matching variant for a consumer's request, and multiple artifact transforms could each be used to accomplish this, then Gradle will fail with an ambiguous transformation error like the following:

[listing]
----
> Could not resolve all dependencies for configuration ':resolveMe'.
   > Found multiple transforms that can produce a variant of project : with requested attributes:
       - color 'red'
       - shape 'round'
     Found the following transforms:
       - From 'configuration ':roundBlueLiquidElements'':
           - With source attributes:
               - color 'blue'
               - shape 'round'
               - state 'liquid'
           - Candidate transform(s):
               - Transform 'BrokenTransform' producing attributes:
                   - color 'red'
                   - shape 'round'
                   - state 'gas'
               - Transform 'BrokenTransform' producing attributes:
                   - color 'red'
                   - shape 'round'
                   - state 'solid'
----

[[sec:variant-visual]]
== Visualizing variant information

[[outgoing_variants_report]]
=== Outgoing variants report

The report task `outgoingVariants` shows the list of variants available for selection by consumers of the project. It displays the capabilities, attributes and artifacts for each variant.

This task is similar to the `dependencyInsight` <<viewing_debugging_dependencies.adoc#sec:identifying-reason-dependency-selection,reporting task>>.

By default, `outgoingVariants` prints information about all variants.
It offers the optional parameter `--variant <variantName>` to select a single variant to display.
It also accepts the `--all` flag to include information about legacy and deprecated configurations, or `--no-all` to exclude this information.

Here is the output of the `outgoingVariants` task on a freshly generated `java-library` project:

[listing]
----
> Task :outgoingVariants
--------------------------------------------------
Variant apiElements
--------------------------------------------------
API elements for the 'main' feature.

Capabilities
    - new-java-library:lib:unspecified (default capability)
Attributes
    - org.gradle.category            = library
    - org.gradle.dependency.bundling = external
    - org.gradle.jvm.version         = 11
    - org.gradle.libraryelements     = jar
    - org.gradle.usage               = java-api
Artifacts
    - build/libs/lib.jar (artifactType = jar)

Secondary Variants (*)

    --------------------------------------------------
    Secondary Variant classes
    --------------------------------------------------
        Description = Directories containing compiled class files for main.

        Attributes
            - org.gradle.category            = library
            - org.gradle.dependency.bundling = external
            - org.gradle.jvm.version         = 11
            - org.gradle.libraryelements     = classes
            - org.gradle.usage               = java-api
        Artifacts
            - build/classes/java/main (artifactType = java-classes-directory)

--------------------------------------------------
Variant mainSourceElements (i)
--------------------------------------------------
Description = List of source directories contained in the Main SourceSet.

Capabilities
    - new-java-library:lib:unspecified (default capability)
Attributes
    - org.gradle.category            = verification
    - org.gradle.dependency.bundling = external
    - org.gradle.verificationtype    = main-sources
Artifacts
    - src/main/java (artifactType = directory)
    - src/main/resources (artifactType = directory)

--------------------------------------------------
Variant runtimeElements
--------------------------------------------------
Runtime elements for the 'main' feature.

Capabilities
    - new-java-library:lib:unspecified (default capability)
Attributes
    - org.gradle.category            = library
    - org.gradle.dependency.bundling = external
    - org.gradle.jvm.version         = 11
    - org.gradle.libraryelements     = jar
    - org.gradle.usage               = java-runtime
Artifacts
    - build/libs/lib.jar (artifactType = jar)

Secondary Variants (*)

    --------------------------------------------------
    Secondary Variant classes
    --------------------------------------------------
        Description = Directories containing compiled class files for main.

        Attributes
            - org.gradle.category            = library
            - org.gradle.dependency.bundling = external
            - org.gradle.jvm.version         = 11
            - org.gradle.libraryelements     = classes
            - org.gradle.usage               = java-runtime
        Artifacts
            - build/classes/java/main (artifactType = java-classes-directory)

    --------------------------------------------------
    Secondary Variant resources
    --------------------------------------------------
        Description = Directories containing the project's assembled resource files for use at runtime.

        Attributes
            - org.gradle.category            = library
            - org.gradle.dependency.bundling = external
            - org.gradle.jvm.version         = 11
            - org.gradle.libraryelements     = resources
            - org.gradle.usage               = java-runtime
        Artifacts
            - build/resources/main (artifactType = java-resources-directory)

--------------------------------------------------
Variant testResultsElementsForTest (i)
--------------------------------------------------
Description = Directory containing binary results of running tests for the test Test Suite's test target.

Capabilities
    - new-java-library:lib:unspecified (default capability)
Attributes
    - org.gradle.category              = verification
    - org.gradle.testsuite.name        = test
    - org.gradle.testsuite.target.name = test
    - org.gradle.testsuite.type        = unit-test
    - org.gradle.verificationtype      = test-results
Artifacts
    - build/test-results/test/binary (artifactType = directory)

(i) Configuration uses incubating attributes such as Category.VERIFICATION.
(*) Secondary variants are variants created via the Configuration#getOutgoing(): ConfigurationPublications API which also participate in selection, in addition to the configuration itself.
----

From this you can see the two main variants that are exposed by a java library, `apiElements` and `runtimeElements`.
Notice that the main difference is on the `org.gradle.usage` attribute, with values `java-api` and `java-runtime`.
As they indicate, this is where the difference is made between what needs to be on the _compile_ classpath of consumers, versus what's needed on the _runtime_ classpath.

It also shows _secondary_ variants, which are exclusive to Gradle projects and not published.
For example, the secondary variant `classes` from `apiElements` is what allows Gradle to skip the JAR creation when compiling against a <<java_library_plugin.adoc#sec:java_library_classes_usage,`java-library` project>>.

==== Information about invalid consumable configurations

A project cannot have multiple configurations with the same attributes and capabilities.
In that case, the project will fail to build.

In order to be able to visualize such issues, the outgoing variant reports handle those errors in a lenient fashion.
This allows the report to display information about the issue.

=== Resolvable configurations report

Gradle also offers a complimentary report task called `resolvableConfigurations` that displays the _resolvable_ configurations of a project, which are those which can have dependencies added and be resolved.  The report will list their attributes and any configurations that they extend.  It will also list a summary of any attributes which will be affected by <<variant_attributes.adoc#sec:abm-compatibility-rules, Compatibility Rules>> or <<variant_attributes.adoc#sec:abm-disambiguation-rules, Disambiguation Rules>> during resolution.

By default, `resolvableConfigurations` prints information about all purely resolvable configurations.
These are configurations that are marked resolvable but *not* marked consumable.
Though some resolvable configurations are also marked consumable, these are legacy configurations that should *not* have dependencies added in build scripts.
This report offers the optional parameter `--configuration <configurationName>` to select a single configuration to display.
It also accepts the `--all` flag to include information about legacy and deprecated configurations, or `--no-all` to exclude this information.
Finally, it accepts the `--recursive` flag to list in the extended configurations section those configurations which are extended _transitively_ rather than directly.
Alternatively, `--no-recursive` can be used to exclude this information.

Here is the output of the `resolvableConfigurations` task on a freshly generated `java-library` project:

[listing]
----
> Task :resolvableConfigurations
--------------------------------------------------
Configuration annotationProcessor
--------------------------------------------------
Description = Annotation processors and their dependencies for source set 'main'.

Attributes
    - org.gradle.category            = library
    - org.gradle.dependency.bundling = external
    - org.gradle.jvm.environment     = standard-jvm
    - org.gradle.libraryelements     = jar
    - org.gradle.usage               = java-runtime

--------------------------------------------------
Configuration compileClasspath
--------------------------------------------------
Description = Compile classpath for source set 'main'.

Attributes
    - org.gradle.category            = library
    - org.gradle.dependency.bundling = external
    - org.gradle.jvm.environment     = standard-jvm
    - org.gradle.jvm.version         = 11
    - org.gradle.libraryelements     = classes
    - org.gradle.usage               = java-api
Extended Configurations
    - compileOnly
    - implementation

--------------------------------------------------
Configuration runtimeClasspath
--------------------------------------------------
Description = Runtime classpath of source set 'main'.

Attributes
    - org.gradle.category            = library
    - org.gradle.dependency.bundling = external
    - org.gradle.jvm.environment     = standard-jvm
    - org.gradle.jvm.version         = 11
    - org.gradle.libraryelements     = jar
    - org.gradle.usage               = java-runtime
Extended Configurations
    - implementation
    - runtimeOnly

--------------------------------------------------
Configuration testAnnotationProcessor
--------------------------------------------------
Description = Annotation processors and their dependencies for source set 'test'.

Attributes
    - org.gradle.category            = library
    - org.gradle.dependency.bundling = external
    - org.gradle.jvm.environment     = standard-jvm
    - org.gradle.libraryelements     = jar
    - org.gradle.usage               = java-runtime

--------------------------------------------------
Configuration testCompileClasspath
--------------------------------------------------
Description = Compile classpath for source set 'test'.

Attributes
    - org.gradle.category            = library
    - org.gradle.dependency.bundling = external
    - org.gradle.jvm.environment     = standard-jvm
    - org.gradle.jvm.version         = 11
    - org.gradle.libraryelements     = classes
    - org.gradle.usage               = java-api
Extended Configurations
    - testCompileOnly
    - testImplementation

--------------------------------------------------
Configuration testRuntimeClasspath
--------------------------------------------------
Description = Runtime classpath of source set 'test'.

Attributes
    - org.gradle.category            = library
    - org.gradle.dependency.bundling = external
    - org.gradle.jvm.environment     = standard-jvm
    - org.gradle.jvm.version         = 11
    - org.gradle.libraryelements     = jar
    - org.gradle.usage               = java-runtime
Extended Configurations
    - testImplementation
    - testRuntimeOnly

--------------------------------------------------
Compatibility Rules
--------------------------------------------------
Description = The following Attributes have compatibility rules defined.

    - org.gradle.dependency.bundling
    - org.gradle.jvm.environment
    - org.gradle.jvm.version
    - org.gradle.libraryelements
    - org.gradle.plugin.api-version
    - org.gradle.usage

--------------------------------------------------
Disambiguation Rules
--------------------------------------------------
Description = The following Attributes have disambiguation rules defined.

    - org.gradle.category
    - org.gradle.dependency.bundling
    - org.gradle.jvm.environment
    - org.gradle.jvm.version
    - org.gradle.libraryelements
    - org.gradle.plugin.api-version
    - org.gradle.usage
----

From this you can see the two main configurations used to resolve dependencies, `compileClasspath` and `runtimeClasspath`, as well as their corresponding test configurations.

[[sec:mapping-maven-ivy-to-variants]]
== Mapping from Maven/Ivy to Gradle variants

Neither Maven nor Ivy have the concept of _variants_, which are only natively supported by Gradle Module Metadata.
Gradle can still work with Maven and Ivy by using different variant derivation strategies.

.Relationship with Gradle Module Metadata
--
Gradle Module Metadata is a metadata format for modules published on Maven, Ivy and other kinds of repositories.
It is similar to the `pom.xml` or `ivy.xml` metadata file, but this format contains details about variants.

See the {metadata-file-spec}[Gradle Module Metadata specification] for more information.
--

[[sec:maven-mapping-to-variants]]
=== Mapping of Maven POM metadata to variants

Modules published on a Maven repository are automatically converted into variant-aware modules.

There is no way for Gradle to know which kind of component was published:

- a BOM that represents a Gradle platform
- a BOM used as a super-POM
- a POM that is both a platform _and_ a library

The default strategy used by Java projects in Gradle is to derive 8 different variants:

* two "library" variants (attribute `org.gradle.category` = `library`)
** the `compile` variant maps the `<scope>compile</scope>` dependencies.
This variant is equivalent to the `apiElements` variant of the <<java_library_plugin.adoc#java_library_plugin,Java Library plugin>>.
All dependencies of this scope are considered _API dependencies_.
** the `runtime` variant maps both the `<scope>compile</scope>` and `<scope>runtime</scope>` dependencies.
This variant is equivalent to the `runtimeElements` variant of the <<java_library_plugin.adoc#java_library_plugin,Java Library plugin>>.
All dependencies of those scopes are considered _runtime dependencies_.
- in both cases, the `<dependencyManagement>` dependencies are _not converted to constraints_
* a "sources" variant that represents the sources jar for the component
* a "javadoc" variant that represents the javadoc jar for the component
* four "platform" variants derived from the `<dependencyManagement>` block (attribute `org.gradle.category` = `platform`):
** the `platform-compile` variant maps the  `<scope>compile</scope>` dependency management dependencies as _dependency constraints_.
** the `platform-runtime` variant maps both the `<scope>compile</scope>` and `<scope>runtime</scope>` dependency management dependencies as _dependency constraints_.
** the `enforced-platform-compile` is similar to `platform-compile` but all the constraints are _forced_
** the `enforced-platform-runtime` is similar to `platform-runtime` but all the constraints are _forced_

You can understand more about the use of platform and enforced platforms variants by looking at the <<platforms.adoc#sec:bom-import, importing BOMs>> section of the manual.
By default, whenever you declare a dependency on a Maven module, Gradle is going to look for the `library` variants.
However, using the `platform` or `enforcedPlatform` keyword, Gradle is now looking for one of the "platform" variants, which allows you to import the constraints from the POM files, instead of the dependencies.

[[sec:ivy-mapping-to-variants]]
=== Mapping of Ivy files to variants

Gradle has no built-in derivation strategy implemented for Ivy files.
Ivy is a flexible format that allows you to publish arbitrary files and can be heavily customized.

If you want to implement a derivation strategy for _compile_ and _runtime_ variants for Ivy, you can do so with <<component_metadata_rules.adoc#component-metadata-rules,component metadata rule>>.
The component metadata rules API allows you to <<component_metadata_rules.adoc#sec:component-metadata-rules-details,access Ivy configurations>> and create variants based on them.
If you know that all the Ivy modules your are consuming have been published with Gradle without further customizations of the `ivy.xml` file, you can add the following rule to your build:

.Deriving compile and runtime variants for Ivy metadata
====
include::sample[dir="snippets/dependencyManagement/customizingResolution-ivyMetadataRule/kotlin",files="build.gradle.kts[tags=ivy-component-metadata-rule]"]
include::sample[dir="snippets/dependencyManagement/customizingResolution-ivyMetadataRule/groovy",files="build.gradle[tags=ivy-component-metadata-rule]"]
====

The rule creates an `apiElements` variant based on the `compile` configuration and a `runtimeElements` variant based on the `default` configuration of each ivy module.
For each variant, it sets the corresponding <<#sec:variant-aware-matching,Java ecosystem attributes>>.
Dependencies and artifacts of the variants are taken from the underlying configurations.
If not all consumed Ivy modules follow this pattern, the rule can be adjusted or only applied to a selected set of modules.

For all Ivy modules without variants, Gradle has a fallback selection method. Gradle does _not_ perform variant aware resolution and instead selects either the `default` configuration or an explicitly named configuration.
