Table of Contents
Gradle builds can declare dependencies on external binaries, raw files and other Gradle projects. You can find examples for common scenarios in this section. For more information, see the full reference on all types of dependencies.
Modern software projects rarely build code in isolation. Projects reference external libraries for the purpose of reusing existing and proven functionality, so-called binary dependencies. Upon resolution binary dependencies are downloaded from dedicated repositories and stored in a cache to avoid unnecessary network traffic.
A typical example for such a library in a Java project is the Spring framework. The following code snippet declares a compile-time dependency on the Spring web module by its coordinates: org.springframework:spring-web:5.0.2.RELEASE
. Gradle resolves the dependency including its transitive dependencies from the Maven Central repository and uses it to compile Java source code. The version attribute of the dependency coordinates points to a concrete version indicating that the underlying artifacts don’t change over time. The use of concrete versions ensures reproducibility for the aspect of dependency resolution.
Example 274. Declaring a binary dependencies with a concrete version
build.gradle
apply plugin: 'java-library' repositories { mavenCentral() } dependencies { implementation 'org.springframework:spring-web:5.0.2.RELEASE' }
A Gradle project can define other types of repositories hosting binary dependencies. You can learn more about the syntax and API in the section on declaring repositories. Refer to The Java Plugin for a deep dive on declaring dependencies for a Java project. The resolution behavior for binary dependencies declarations is highly customizable.
Projects might adopt a more aggressive approach for consuming binary dependencies. For example you might want to always integrate the latest version of a dependency to consume cutting edge features at any given time. A dynamic version allows for resolving the latest version or the latest version of a version range for a given dependency.
Using dynamic versions in a build bears the risk of potentially breaking it. As soon as a new version of the dependency is released that contains an incompatible API change your source code might stop compiling.
Example 275. Declaring a binary dependencies with a dynamic version
build.gradle
apply plugin: 'java-library' repositories { mavenCentral() } dependencies { implementation 'org.springframework:spring-web:5.+' }
A build scan can effectively visualize dynamic dependency versions and their respective, selected versions.
By default, Gradle caches dynamic versions of dependencies for 24 hours. The threshold can be configured as needed for example if you want to resolve new versions earlier.
A team might decide to implement a series of features before releasing a new version of the application or library. A common strategy to allow consumers to integrate an unfinished version of their artifacts early and often is to release a so-called changing version. A changing version indicates that the feature set is still under active development and hasn’t released a stable version for general availability yet.
In Maven repositories, changing versions are commonly referred to as snapshot versions. Snapshot versions contain the suffix -SNAPSHOT
. The following example demonstrates how to declare a snapshot version on the Spring dependency.
Example 276. Declaring a binary dependencies with a changing version
build.gradle
apply plugin: 'java-library' repositories { mavenCentral() maven { url 'https://repo.spring.io/snapshot/' } } dependencies { implementation 'org.springframework:spring-web:5.0.3.BUILD-SNAPSHOT' }
By default, Gradle caches changing versions of dependencies for 24 hours. The threshold can be configured as needed for example if you want to resolve new snapshot versions earlier.
Gradle is flexible enough to treat any version as changing version. All you need to do is to set the property ExternalModuleDependency.setChanging(boolean)
to true
.
Projects sometimes do not rely on a binary repository product e.g. JFrog Artifactory or Sonatype Nexus for hosting and resolving external dependencies. It’s common practice to host those dependencies on a shared drive or check them into version control alongside the project source code. Those dependencies are referred to as file dependencies, the reason being that they represent a files without any metadata (like information about transitive dependencies, the origin or its author) attached to them.
The following example resolves file dependencies from the directories ant
, libs
and tools
.
Example 277. Declaring multiple file dependencies
build.gradle
configurations { antContrib externalLibs deploymentTools } dependencies { antContrib files('ant/antcontrib.jar') externalLibs files('libs/commons-lang.jar', 'libs/log4j.jar') deploymentTools fileTree(dir: 'tools', include: '*.exe') }
As you can see in the code example, every dependency has to define its exact location in the file system. The most prominent methods for creating a file reference are Project.files(java.lang.Object[])
and Project.fileTree(java.lang.Object)
. Alternatively, you can also define the source directory of one or many file dependencies in the form of a flat directory repository.
Software projects often break up software components into modules to improve maintainability and prevent strong coupling. Modules can define dependencies between each other to reuse code within the same project.
Gradle can model dependencies between modules. Those dependencies are called project dependencies because each module is represented by a Gradle project. At runtime, the build automatically ensures that project dependencies are built in the correct order and added to the classpath for compilation. The chapter Authoring Multi-Project Builds discusses how to set up and configure multi-project builds in more detail.
The following example declares the dependencies on the utils
and api
project from the web-service
project. The method Project.project(java.lang.String)
creates a reference to a specific subproject by path.
Example 278. Declaring project dependencies
build.gradle
project(':web-service') { dependencies { implementation project(':utils') implementation project(':api') } }
Every dependency declared for a Gradle project applies to a specific scope. For example some dependencies should be used for compiling source code whereas others only need to be available at runtime. Gradle represents the scope of a dependency with the help of a Configuration
.
Many Gradle plugins add pre-defined configurations to your project. The Java plugin, for example, adds configurations to represent the various classpaths it needs for source code compilation, executing tests and the like. See the Java plugin chapter for an example. The sections above demonstrate how to declare dependencies for different use cases.
You can also define configurations yourself, so-called custom configurations. A custom configuration is useful for separating the scope of dependencies needed for a dedicated purpose.
Let’s say you wanted to declare a dependency on the Jasper Ant task for the purpose of pre-compiling JSP files that should not end up in the classpath for compiling your source code. It’s fairly simply to achieve that goal by introducing a custom configuration and using it in a task.
Example 279. Declaring and using a custom configuration
build.gradle
configurations { jasper } repositories { mavenCentral() } dependencies { jasper 'org.apache.tomcat.embed:tomcat-embed-jasper:9.0.2' } task preCompileJsps { doLast { ant.taskdef(classname: 'org.apache.jasper.JspC', name: 'jasper', classpath: configurations.jasper.asPath) ant.jasper(validateXml: false, uriroot: file('src/main/webapp'), outputDir: file("$buildDir/compiled-jsps")) } }
A project’s configurations are managed by a configurations
object. Configurations have a name and can extend each other. To learn more about this API have a look at ConfigurationContainer
.
Whenever Gradle tries to resolve a dependency from a Maven or Ivy repository, it looks for a metadata file and the default artifact file, a JAR. The build fails if none of these artifact files can be resolved. Under certain conditions, you might want to tweak the way Gradle resolves artifacts for a dependency.
The dependency only provides a non-standard artifact without any metadata e.g. a ZIP file.
The dependency metadata declares more than one artifact e.g. as part of an Ivy dependency descriptor.
You only want to download a specific artifact without any of the transitive dependencies declared in the metadata.
Gradle is a polyglot build tool and not limited to just resolving Java libraries. Let’s assume you wanted to build a web application using JavaScript as the client technology. Most projects check in external JavaScript libraries into version control. An external JavaScript library is no different than a reusable Java library so why not download it from a repository instead?
Google Hosted Libraries is a distribution platform for popular, open-source JavaScript libraries. With the help of the artifact-only notation you can download a JavaScript library file e.g. JQuery. The @
character separates the dependency’s coordinates from the artifact’s file extension.
Example 280. Resolving a JavaScript artifact for a declared dependency
build.gradle
repositories { ivy { url 'https://ajax.googleapis.com/ajax/libs' layout 'pattern', { artifact '[organization]/[revision]/[module].[ext]' } } } configurations { js } dependencies { js 'jquery:jquery:3.2.1@js' }
Some dependencies ship different "flavors" of the same artifact or they publish multiple artifacts that belong to a specific version of the dependency but have a different purpose. It’s common for a Java library to publish the artifact with the compiled class files, another one with just the source code in it and a third one containing the Javadocs.
In JavaScript, a library may exist as uncompressed or minified artifact. In Gradle, a specific artifact identifier is called classifier, a term generally used in Maven and Ivy dependency management.
Let’s say we wanted to download the minified artifact of the JQuery library instead of the uncompressed file. You can provide the classifier min
as part of the dependency declaration.
Example 281. Resolving a JavaScript artifact with classifier for a declared dependency
build.gradle
repositories { ivy { url 'https://ajax.googleapis.com/ajax/libs' layout 'pattern', { artifact '[organization]/[revision]/[module](.[classifier]).[ext]' } } } configurations { js } dependencies { js 'jquery:jquery:3.2.1:min@js' }