# 1. Declaring dependencies

version 8.14.4

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.

build.gradle

    dependencies {
        // Configuration Name + Dependency Notation - GroupID : ArtifactID (Name) : Version
        configuration('<group>:<name>:<version>')
    }

Note:

1. Gradle automatically includes transitive dependencies, which are dependencies of your dependencies.

2. 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.

3. 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:

build.gradle.kts

    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")
    }

build.gradle

    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:

build.gradle.kts

    dependencies {
        implementation(project(":utils"))
        implementation(project(":api"))
    }

build.gradle

    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:

build.gradle.kts

    dependencies {
        runtimeOnly(files("libs/a.jar", "libs/b.jar"))
        runtimeOnly(fileTree("libs") { include("*.jar") })
    }

build.gradle

    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:

InitializeCollection.java

    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:

build.gradle.kts

    dependencies {
        implementation("com.google.guava:guava:23.0")
    }

build.gradle

    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:

build.gradle.kts

    dependencies {
        implementation("com.google.guava:guava:30.0-jre")
        runtimeOnly("org.apache.commons:commons-lang3:3.14.0")
    }

build.gradle

    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 >>