When we develop our code, we usually use third-party or open source libraries. These libraries need to be available in the classpath of the compiler, otherwise we will get errors and our build will fail. Gradle provides support for dependency management, so we can define our dependencies in our build file. Gradle will then take care of the necessary configuration for our various tasks.
In this chapter, we will learn how we can use dependency management in our builds. We will see how to organize dependencies with configurations. We will also learn about repositories that host dependency artifacts, their dependencies, and how we can handle different repository layouts.
Then we will define dependencies using Gradle syntax, for modules with version information.
Java has no real support for working with versioned libraries as dependencies. We cannot express in Java whether our class depends on lib-1.0.jar
or lib-2.0.jar
, for example. There are some open source solutions that deal with dependencies and allow us to express whether our Java code depends on lib-1.0.jar
or lib-2.0.jar
. The most popular are Maven and Apache Ivy. Maven is a complete build tool and has a mechanism for dependency management. Ivy is only about dependency management.
Both tools support repositories where versioned libraries are stored, together with metadata about those libraries. A library can have dependencies on other libraries and is described in the metadata of the library. The metadata is described in descriptor XML files. Ivy fully supports Maven descriptor files and repositories; it also adds some extra functionality. So with Ivy, you get what you would with Maven, and then some more. That is why Gradle uses the Ivy API under the hood to do dependency management. Gradle also adds some extra sugar on top of Ivy, so we can define and use dependencies in a very flexible way.
In a Gradle build file, we group dependencies together in a configuration. A configuration has a name, and configurations can extend each other. With a configuration, we can make logical groups of dependencies. For example, we can create a javaCompile
configuration to include dependencies needed to compile the Java code. We can add as many configurations to our build as we want to. We don't define our dependencies directly in the configuration. A configuration, as with a label, can be used when we define a dependency.
Every Gradle build has a ConfigurationContainer
object. This object is accessible via the Project
property containers. We can use a closure to configure the container with Configuration
objects. Each Configuration
object has at least a name, but we can change more properties. We can set a resolution strategy, if a configuration has version conflicts with dependencies, or we can change the visibility of a configuration so that it will not be visible outside of our project.
In the following example, we create a new configuration with the name commonsLib
to hold our dependencies and a configuration mainLib
that extends commonsLib
. The extended configuration mainLib
gets all settings and dependencies from commonsLib
, and we can assign extra dependencies as well:
configurations { commonsLib { description = 'Common libraries' } mainLib { description = 'Main libraries' extendsFrom commonsLib } } println configurations['mainLib'].name println configurations.commonsLib.name
The output of the build shows the names of the configurations:
$ gradle –q commonsLib mainLib
Many plugins add new configurations to ConfigurationContainer
. We used the Java plugin in the previous chapter, which added four configurations to our project. With the built-in task dependencies, we can get an overview of defined dependencies and configurations for a project.
The following build script uses the Java plugin:
apply plugin: 'java'
We get the following output if we execute the dependencies
task:
$ gradle –q dependencies ------------------------------------------------------------ Root project ------------------------------------------------------------ archives - Configuration for archive artifacts. No dependencies compile - Classpath for compiling the main sources. No dependencies default - Configuration for default artifacts. No dependencies runtime - Classpath for running the compiled main classes. No dependencies testCompile - Classpath for compiling the test sources. No dependencies testRuntime - Classpath for running the compiled test classes. No dependencies
Notice how we already have six configurations in our project. The following table shows the configuration and which tasks use the configuration:
Configuration |
Extends |
Used by task |
Description |
---|---|---|---|
- |
|
Dependencies needed at compile time to compile the source files. | |
|
- |
Dependencies for runtime of the application, but not needed for compilation. | |
|
|
Dependencies to compile test source files. | |
|
|
All dependencies needed to run the tests. | |
- |
|
Contains artifacts, such as JAR files created by the project. | |
|
- |
Default configuration contains all runtime dependencies. |
If our code has a dependency on a library, we can set the dependency with the compile configuration. The dependency is then automatically available in the runtime
, testCompile
, testRuntime
, and default
configurations.
18.189.180.43