// Copyright (C) 2024 Gradle, Inc.
//
// Licensed under the Creative Commons Attribution-Noncommercial-ShareAlike 4.0 International License.;
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      https://creativecommons.org/licenses/by-nc-sa/4.0/
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

[[part3_gradle_dep_man]]
= Part 3: Dependency Management

Learn the basics of project dependencies and Gradle's dependency management.

****
**In this section you will:**

- Understand project dependencies
- Inspect project dependencies
- Use a Build Scan to analyze dependencies
- Update project dependencies
- Understand transitive dependencies
- Adding a version catalog
****

[[part3_begin]]
== Step 0. Before you Begin

1. You initialized your Java app in <<part1_gradle_init.adoc#part1_begin,part 1>>.
2. You ran several tasks in <<part2_gradle_tasks#part2_begin,part 2>>.

== Step 1. Understanding the Version Catalog
A version catalog is used to declare all direct dependencies of a project in a central location.

It is created by Gradle init in `gradle/libs.versions.toml` and referenced in subproject build files.

.libs.versions.toml
[source,text]
----
[versions]
guava = "32.1.2-jre"
junit-jupiter = "5.10.0"

[libraries]
guava = { module = "com.google.guava:guava", version.ref = "guava" }
junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit-jupiter" }
----

To reference the libraries defined in the version catalog:

[.multi-language-sample]
=====
[source, kotlin]
----
dependencies {
    implementation(libs.guava)
    testImplementation(libs.junit.jupiter)
}
----
=====
[.multi-language-sample]
=====
[source, groovy]
----
dependencies {
    implementation libs.guava
    testImplementation libs.junit.jupiter
}
----
=====

In this example, `libs.guava` and `libs.junit.jupiter` refer to the corresponding libraries defined in your version catalog.

TIP: The `libs.junit.jupiter` syntax is used because the key contains a hyphen which is a special character.

A version catalog provides a number of advantages over declaring dependencies directly in build scripts:

- Gradle generates type-safe accessors from the catalog so that you can easily add dependencies with autocompletion in the IDE.
- It is a central place to declare a version of a dependency so that any changes apply to every subproject.

== Step 2. Understanding Project Dependencies
Gradle provides excellent support for dependency management and automation.

Let's take another look at our build script (the `build.gradle(.kts)` file), specifically the following section:
[.multi-language-sample]
=====
[source, kotlin]
----
repositories {
    // Use Maven Central for resolving dependencies.
    mavenCentral()
}

dependencies {
    // Use JUnit Jupiter for testing.
    testImplementation(libs.junit.jupiter)

    testRuntimeOnly("org.junit.platform:junit-platform-launcher")

    // This dependency is used by the application.
    implementation(libs.guava)
}
----
=====
[.multi-language-sample]
=====
[source, groovy]
----
repositories {
    // Use Maven Central for resolving dependencies.
    mavenCentral()
}

dependencies {
    // Use JUnit Jupiter for testing.
    testImplementation libs.junit.jupiter

    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'

    // This dependency is used by the application.
    implementation libs.guava
}
----
=====

Some key concepts in Gradle dependency management include:

*Repositories* - The source of dependencies -> `mavenCentral()`

https://mvnrepository.com/repos/central[Maven Central] is a collection of jar files, plugins, and libraries provided by the Maven community and backed by https://central.sonatype.org/[Sonatype^].
It is the de-facto public artifact store for Java and is used by many build systems.

*Dependencies* - Dependencies declared via configuration types -> https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api[`libs.junit.jupiter`] and https://mvnrepository.com/artifact/com.google.guava/guava[`libs.guava`] +

Gradle needs specific information to find a dependency.
Let's look at `libs.guava` -> `com.google.guava:guava:32.1.2-jre` and `libs.junit.jupiter` -> `org.junit.jupiter:junit-jupiter-api:5.9.1`; they are broken down as follows:

[cols="10h,30,40,20"]
|===
| |Description | com.google.guava:guava:32.1.2-jre | org.junit.jupiter:junit-jupiter-api:5.9.1

|Group
|identifier of an organization
|`com.google.guava`
|`org.junit.jupiter`

|Name
|dependency identifier
|`guava`
|`junit-jupiter-api`

|Version
|version # to import
|`32.1.2-jre`
|`5.9.1`
|===

== Step 3. Understanding Transitive Dependencies
A _transitive dependency_ is a dependency of a dependency.

For our `guava` dependency to work, it requires a library called `failureaccess`.
Therefore `failureaccess` is a transitive dependency of the project.

== Step 4. Viewing Project Dependencies
You can view your dependency tree in the terminal using the `./gradlew :app:dependencies` command:
[source,kotlin]
----
$ ./gradlew :app:dependencies

> Task :app:dependencies

------------------------------------------------------------
Project ':app'
------------------------------------------------------------

...

compileClasspath - Compile classpath for source set 'main'.
\--- com.google.guava:guava:32.1.2-jre
     +--- com.google.guava:guava-parent:32.1.2-jre
     |    +--- com.google.code.findbugs:jsr305:3.0.2 (c)
     |    +--- org.checkerframework:checker-qual:3.33.0 (c)
     |    +--- com.google.errorprone:error_prone_annotations:2.18.0 (c)
     |    \--- com.google.j2objc:j2objc-annotations:2.8 (c)
     +--- 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.33.0
     +--- com.google.errorprone:error_prone_annotations -> 2.18.0
     \--- com.google.j2objc:j2objc-annotations -> 2.8

----

The output clearly depicts that `com.google.guava:guava:32.1.2-jre` has a dependency on `com.google.guava:failureaccess:1.0.1`.

== Step 5. Viewing Dependencies in a Build Scan®
To view dependencies using a https://scans.gradle.com/[Build Scan], run the build task with an optional `--scan` flag.

In the `tutorial` directory, enter the command below and follow the prompt to accept the terms:
[source,text]
----
$ ./gradlew build --scan

BUILD SUCCESSFUL in 423ms
7 actionable tasks: 7 up-to-date

Publishing a build scan to scans.gradle.com requires accepting the Gradle Terms of Service defined at https://gradle.com/terms-of-service. Do you accept these terms? [yes, no] yes

Gradle Terms of Service accepted.

Publishing build scan...
https://gradle.com/s/link
----

A https://scans.gradle.com/[Build Scan] is a shareable and centralized record of a build and is available as a free service from Gradle.

Click the link provided in the prompt: `https://gradle.com/s/link`.

WARNING: You will have to accept the terms of service to use Build Scans.

You will need to activate the Build Scan by using your email:

image::tutorial/build-scan-prompt.png[]

You will receive the final link to the scan in your inbox which should look as follows:

image::tutorial/build-scan-results.png[]

Open the **Dependencies** tab in the menu and expand `compileClasspath`, `runtimeClasspath`, `testCompileClasspath`, and `testRuntimeClasspath`:

image::tutorial/build-scan-dependencies.png[]

As expected, we can see the declared dependencies `junit` and `guava` are used by Gradle to compile, run, and test the app.

Expand `com.google.guava:guava:32.1.2-jre` and `org.junit.jupiter:junit-jupiter:5.9.1` in the window:

image::tutorial/build-scan-trans-dependencies.png[]

There are several transitive dependencies under `junit` and `guava`.
For example, the `com.google.code.findbugs:jsr305:3.0.2` transitive dependency comes from the `com.google.guava:guava:32.1.2-jre` dependency.

== Step 6. Updating Project Dependencies
Adding and changing dependencies is done in the build file and in the version catalog.

Let's change the `guava` version and look at how this affects the dependency tree.

Change the `guava` dependency in the version catalog to:

.gradle/libs.versions.toml
[source,text]
----
[versions]
guava = "30.0-jre"
junit-jupiter = "5.10.0"

[libraries]
guava = { module = "com.google.guava:guava", version.ref = "guava" }
junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit-jupiter" }
----

If you change the file using IntelliJ, don't forget to click the `sync` Gradle button:

image::tutorial/intellij-idea-dep-man.png[]

Run `./gradlew build --scan` and view the Build Scan results:

image::tutorial/build-scan-change.png[]

Run `./gradlew :app:dependencies` in the terminal to check the changes in the dependency tree:

[source,text]
----
...

compileClasspath - Compile classpath for 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

...
----

It is clear the `guava` dependency has been updated to version `30.0` and the transitive dependencies have changed as well.

== Step 7. Run the Java app
Finally, make sure everything is working using the `run` task, either in your terminal or IDE:
----
./gradlew run

> Task :app:compileJava UP-TO-DATE
> Task :app:processResources NO-SOURCE
> Task :app:classes UP-TO-DATE

> Task :app:run
Hello World!
----

[.text-right]
**Next Step:** <<part4_gradle_plugins#part4_begin,Applying Plugins>> >>
