1. Declaring dependencies
Declaring dependencies in Gradle involves specifying libraries or files that your project depends on.
Understanding producers and consumers
In dependency management, it is essential to understand the distinction between producers and consumers.
When you build a library, you are acting as a producer, creating artifacts that will be consumed by others, the consumers.
When you depend on that library, you are acting as a consumer. Consumers can be broadly defined as:
-
Projects that depend on other projects.
-
Configurations that declare dependencies on specific artifacts.
The decisions we make in dependency management often depend on the type of project we are building, specifically, what kind of consumer we are.
Adding a dependency
To add a dependency in Gradle, you use the dependencies{}
block in your build script.
The dependencies
block allows you to specify various types of dependencies such as external libraries, local JAR files, or other projects within a multi-project build.
External dependencies in Gradle are declared using a configuration name (e.g., implementation
, compileOnly
, testImplementation
) followed by the dependency notation, which includes the group ID (group), artifact ID (name), and version.
dependencies {
// Configuration Name + Dependency Notation - GroupID : ArtifactID (Name) : Version
configuration('<group>:<name>:<version>')
}
Note:
-
Gradle automatically includes transitive dependencies, which are dependencies of your dependencies.
-
Gradle offers several configuration options for dependencies, which define the scope in which dependencies are used, such as compile-time, runtime, or test-specific scenarios.
-
You can specify the repositories where Gradle should look for dependencies in your build file.
Understanding types of dependencies
There are three kinds of dependencies, module dependencies, project dependencies, and file dependencies.
1. Module dependencies
Module dependencies are the most common dependencies. They refer to a module in a repository:
dependencies {
implementation("org.codehaus.groovy:groovy:3.0.5")
implementation("org.codehaus.groovy:groovy-json:3.0.5")
implementation("org.codehaus.groovy:groovy-nio:3.0.5")
}
dependencies {
implementation 'org.codehaus.groovy:groovy:3.0.5'
implementation 'org.codehaus.groovy:groovy-json:3.0.5'
implementation 'org.codehaus.groovy:groovy-nio:3.0.5'
}
2. Project dependencies
Project dependencies allow you to declare dependencies on other projects within the same build. This is useful in multi-project builds where multiple projects are part of the same Gradle build.
Project dependencies are declared by referencing the project path:
dependencies {
implementation(project(":utils"))
implementation(project(":api"))
}
dependencies {
implementation project(':utils')
implementation project(':api')
}
3. File dependencies
In some projects, you might not rely on binary repository products like JFrog Artifactory or Sonatype Nexus for hosting and resolving external dependencies. Instead, you might host these dependencies on a shared drive or to check them into version control alongside the project source code.
These are known as file dependencies because they represent files without any metadata (such as information about transitive dependencies, origin, or author) attached to them.
To add files as dependencies for a configuration, you simply pass a file collection as a dependency:
dependencies {
runtimeOnly(files("libs/a.jar", "libs/b.jar"))
runtimeOnly(fileTree("libs") { include("*.jar") })
}
dependencies {
runtimeOnly files('libs/a.jar', 'libs/b.jar')
runtimeOnly fileTree('libs') { include '*.jar' }
}
It is recommended to use project dependencies or external dependencies over file dependencies. |
Looking at an example
Let’s imagine an example for a Java application which uses Guava, a set of core Java libraries from Google:
The Java app contains the following Java class:
package org.example;
import com.google.common.collect.ImmutableMap; // Comes from the Guava library
public class InitializeCollection {
public static void main(String[] args) {
ImmutableMap<String, Integer> immutableMap
= ImmutableMap.of("coin", 3, "glass", 4, "pencil", 1);
}
}
To add the Guava library to your Gradle project as a dependency, you must add the following line to your build file:
dependencies {
implementation("com.google.guava:guava:23.0")
}
Where:
-
implementation
is the configuration. -
com.google.guava:guava:23.0
specifies the group, name, and version of the library:-
com.google.guava
is the group ID. -
guava
is the artifact ID (i.e., name). -
23.0
is the version.
-
Take a quick look at the Guava page in Maven Central as a reference.
Listing project dependencies
The dependencies
task provides an overview of the dependencies of your project.
It helps you understand what dependencies are being used, how they are resolved, and their relationships, including any transitive dependencies by rendering a dependency tree from the command line.
This task can be particularly useful for debugging dependency issues, such as version conflicts or missing dependencies.
For example, let’s say our app
project contains the follow lines in its build script:
dependencies {
implementation("com.google.guava:guava:30.0-jre")
runtimeOnly("org.apache.commons:commons-lang3:3.14.0")
}
dependencies {
implementation("com.google.guava:guava:30.0-jre")
runtimeOnly("org.apache.commons:commons-lang3:3.14.0")
}
Running the dependencies
task on the app
project yields the following:
$ ./gradlew app:dependencies > Task :app:dependencies ------------------------------------------------------------ Project ':app' ------------------------------------------------------------ implementation - Implementation dependencies for the 'main' feature. (n) \--- com.google.guava:guava:30.0-jre (n) runtimeClasspath - Runtime classpath of source set 'main'. +--- com.google.guava:guava:30.0-jre | +--- com.google.guava:failureaccess:1.0.1 | +--- com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava | +--- com.google.code.findbugs:jsr305:3.0.2 | +--- org.checkerframework:checker-qual:3.5.0 | +--- com.google.errorprone:error_prone_annotations:2.3.4 | \--- com.google.j2objc:j2objc-annotations:1.3 \--- org.apache.commons:commons-lang3:3.14.0 runtimeOnly - Runtime-only dependencies for the 'main' feature. (n) \--- org.apache.commons:commons-lang3:3.14.0 (n)
We can clearly see that for the implementation
configuration, the com.google.guava:guava:30.0-jre
dependency has been added.
As for the runtimeOnly
configuration, the org.org.apache.commons:commons-lang3:3.14.0
dependency has been added.
We also see a list of transitive dependencies for com.google.guava:guava:30.0-jre
(which are the dependencies for the guava
library), such as com.google.guava:failureaccess:1.0.1
in the runtimeClasspath
configuration.
Next Step: Learn about Dependency Configurations >>