Working with Dependencies

For the examples below we have the following dependencies setup:

Example 296. Configuration.copy

build.gradle

configurations {
    sealife
    alllife
}

dependencies {
    sealife "sea.mammals:orca:1.0", "sea.fish:shark:1.0", "sea.fish:tuna:1.0"
    alllife configurations.sealife
    alllife "air.birds:albatross:1.0"
}

The dependencies have the following transitive dependencies:

shark-1.0 -> seal-2.0, tuna-1.0

orca-1.0 -> seal-1.0

tuna-1.0 -> herring-1.0

You can use the configuration to access the declared dependencies or a subset of those:

Example 297. Accessing declared dependencies

build.gradle

task dependencies {
    doLast {
        configurations.alllife.dependencies.each { dep -> println dep.name }
        println()
        configurations.alllife.allDependencies.each { dep -> println dep.name }
        println()
        configurations.alllife.allDependencies.findAll { dep -> dep.name != 'orca' }
            .each { dep -> println dep.name }
    }
}

Output of gradle -q dependencies

> gradle -q dependencies
albatross

albatross
orca
shark
tuna

albatross
shark
tuna

The dependencies task returns only the dependencies belonging explicitly to the configuration. The allDependencies task includes the dependencies from extended configurations.

To get the library files of the configuration dependencies you can do:

Example 298. Configuration.files

build.gradle

task allFiles {
    doLast {
        configurations.sealife.files.each { file ->
            println file.name
        }
    }
}

Output of gradle -q allFiles

> gradle -q allFiles
orca-1.0.jar
shark-1.0.jar
tuna-1.0.jar
seal-2.0.jar
herring-1.0.jar

Sometimes you want the library files of a subset of the configuration dependencies (e.g. of a single dependency).

Example 299. Configuration.files with spec

build.gradle

task files {
    doLast {
        configurations.sealife.files { dep -> dep.name == 'orca' }.each { file ->
            println file.name
        }
    }
}

Output of gradle -q files

> gradle -q files
orca-1.0.jar
seal-2.0.jar

The Configuration.files method always retrieves all artifacts of the whole configuration. It then filters the retrieved files by specified dependencies. As you can see in the example, transitive dependencies are included.

You can also copy a configuration. You can optionally specify that only a subset of dependencies from the original configuration should be copied. The copying methods come in two flavors. The copy method copies only the dependencies belonging explicitly to the configuration. The copyRecursive method copies all the dependencies, including the dependencies from extended configurations.

Example 300. Configuration.copy

build.gradle

task copy {
    doLast {
        configurations.alllife.copyRecursive { dep -> dep.name != 'orca' }
            .allDependencies.each { dep -> println dep.name }
        println()
        configurations.alllife.copy().allDependencies
            .each { dep -> println dep.name }
    }
}

Output of gradle -q copy

> gradle -q copy
albatross
shark
tuna

albatross

It is important to note that the returned files of the copied configuration are often but not always the same than the returned files of the dependency subset of the original configuration. In case of version conflicts between dependencies of the subset and dependencies not belonging to the subset the resolve result might be different.

Example 301. Configuration.copy vs. Configuration.files

build.gradle

task copyVsFiles {
    doLast {
        configurations.sealife.copyRecursive { dep -> dep.name == 'orca' }
            .each { file -> println file.name }
        println()
        configurations.sealife.files { dep -> dep.name == 'orca' }
            .each { file -> println file.name }
    }
}

Output of gradle -q copyVsFiles

> gradle -q copyVsFiles
orca-1.0.jar
seal-1.0.jar

orca-1.0.jar
seal-2.0.jar

In the example above, orca has a dependency on seal-1.0 whereas shark has a dependency on seal-2.0. The original configuration has therefore a version conflict which is resolved to the newer seal-2.0 version. The files method therefore returns seal-2.0 as a transitive dependency of orca. The copied configuration only has orca as a dependency and therefore there is no version conflict and seal-1.0 is returned as a transitive dependency.

Once a configuration is resolved it is immutable. Changing its state or the state of one of its dependencies will cause an exception. You can always copy a resolved configuration. The copied configuration is in the unresolved state and can be freshly resolved.

To learn more about the API of the configuration class see the API documentation: Configuration.