Throughout the development process, dependency management becomes a cornerstone when projects increase over time, and solutions become sophisticated to optimize code or try to be more scalable. Clearly, having tools like Gradle helps to handle and centralize the dependencies impacting the development performance, reducing potential errors, removing redundant libraries, and optimizing the code with the tools used.

Gradle is an open-source build automation tool initially created for Java projects, but it also accommodates to various programming languages like Groovy, Kotlin, and Scala. It plays a crucial role in Android development, where it serves as the default build system.

The inclusion of the Version Catalog available from version 7.0 improved the dependencies consistency, centralizing the version definitions in one location across multiple projects.

Let’s explore the concepts and benefits of Version Catalogs, understand how they function in Android projects, and learn how to apply them in a Spring Boot project.

Why Should You Use a Gradle Version Catalog?

In the realm of modern software development, tools like Gradle version catalogs have emerged as a sophisticated solution for handling dependencies. These catalogs offer an advanced approach that aligns perfectly with the evolving needs of contemporary projects.

By implementing version catalogs, development teams can streamline their dependency management process, ensuring greater consistency and efficiency across various modules and applications. This method not only simplifies the overall workflow but also enhances adaptability to the ever-changing landscape of software libraries and frameworks.

Ultimately, Gradle version catalogs provide a scalable, maintainable way to manage dependencies, supporting teams in their commitment to delivering high-quality, cutting-edge software solutions. As projects grow in complexity and scale, this approach becomes increasingly valuable, allowing developers to focus more on innovation and less on the intricacies of dependency coordination.

As we delve deeper into the practical benefits of Gradle version catalogs, several key advantages come to light, showing why this approach has gained traction in the development community:

  • Centralized Dependency Management: By storing dependency versions in one location, teams can maintain consistency across multiple projects. Any updates made to the version catalog are automatically reflected in all projects that reference it, minimizing the risk of version mismatches.
  • Easier Updates: When a new version of a library is released, developers can simply update the version number in the catalog. This ease of maintenance is particularly beneficial in large projects with numerous dependencies, such as Android applications, where managing versions manually can be tedious and error-prone.
  • Improved Readability: Using a version catalog enhances the readability of build scripts. Instead of cluttering the build files with version numbers, developers can use meaningful names defined in the catalog, making it easier to understand what dependencies are being used.
  • Support for Multiple Dependency Types: The version catalog can manage not only library dependencies but also plugin versions, which further centralizes and simplifies the build configuration.

Given these compelling advantages, let’s explore the practical steps to implement this powerful tool in Android and Spring Boot projects.

How to Set Up a Gradle Version Catalog

Modern Android apps can be created using the Gradle Version Catalog by default. However, Java projects developed with Spring Boot using Gradle don’t have native support for it, but a migration to use the catalog is possible and beneficial.

For an Android Project

Let’s take a look at how a Gradle Version Catalog is structured in an Android app. You’ll find a libs.versions.toml file within the gradle directory of your project. This file contains a list of dependencies along with their corresponding versions. For example:

[versions]
kotlin = "1.7.10"
androidGradlePlugin = "7.1.2"

[libraries]
kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" }
android-coreKtx = { module = "androidx.core:core-ktx", version = "1.8.0" }

[plugins]
android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" }

In the module’s build.gradle.kts file, reference the dependencies to use the catalog:

dependencies {
    implementation(libs.kotlin.stdlib)
    implementation(libs.android.coreKtx)
}

For plugins, on the build.gradle.kts (project-level) file:

plugins {
    alias(libs.plugins.android.application)
}

This approach is beneficial for managing dependencies in Android projects. But what about legacy Android apps? Or how can we implement Gradle Version Catalogs in an existing Spring Boot project? Let’s dive into how to integrate this feature into an existing project, whether it’s an Android or Spring Boot app. Additionally, while you can write Gradle files in either Groovy or Kotlin, we’ll continue using Kotlin in this example.

Gradle Version Catalog in an existing Spring Boot app

To set up a Gradle Version Catalog in an existing Spring Boot app, you’ll centralize the management of dependency versions and simplify your build.gradle.kts file by creating a libs.versions.toml file in the gradle directory of your project. This file will hold the versions and coordinates for the dependencies used in your project.

First of all, let’s take a look at the original build.gradle.kts

plugins {
  java
  id("org.springframework.boot") version "3.3.2"
  id("io.spring.dependency-management") version "1.1.6"
}

group = "co.wawand.server"
version = "0.0.1-SNAPSHOT"

java {
  toolchain {
    languageVersion = JavaLanguageVersion.of(17)
  }
}

configurations {
  compileOnly {
    extendsFrom(configurations.annotationProcessor.get())
  }
}

repositories {
  mavenCentral()
}

dependencies {
  implementation("org.springframework.boot:spring-boot-starter-data-jpa")
  implementation("org.springframework.boot:spring-boot-starter-web")

  compileOnly("org.projectlombok:lombok")
  runtimeOnly("com.h2database:h2")
  annotationProcessor("org.projectlombok:lombok")

  testImplementation("org.springframework.boot:spring-boot-starter-test")
  testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}

tasks.withType<Test> {
  useJUnitPlatform()
}

Now, let’s start to build the libs.versions.toml file based on the previous build.gradle file:

[versions]
springBoot = "3.3.2"
lombok = "1.18.24"
h2database = "2.1.214"
junitPlatform = "1.8.2"
dependencyManagement = "1.1.6"

[libraries]
springBootStarterDataJpa = { module = "org.springframework.boot:spring-boot-starter-data-jpa", version.ref = "springBoot" }
springBootStarterWeb = { module = "org.springframework.boot:spring-boot-starter-web", version.ref = "springBoot" }
lombok = { module = "org.projectlombok:lombok", version.ref = "lombok" }
h2 = { module = "com.h2database:h2", version.ref = "h2database" }
junitPlatformLauncher = { module = "org.junit.platform:junit-platform-launcher", version.ref = "junitPlatform" }

[plugins]
springBoot = { id = "org.springframework.boot", version.ref = "springBoot" }
dependencyManagement = { id = "io.spring.dependency-management", version.ref = "dependencyManagement" }

After centralizing all the dependencies and plugins and specifying their versions, proceed to update the build script to reflect these changes in the build.gradle.kts file.

plugins {
    java
    alias(libs.plugins.springBoot)
    alias(libs.plugins.dependencyManagement)
}

group = "co.wawand.server"
version = "0.0.1-SNAPSHOT"

java {
    toolchain {
        languageVersion.set(JavaLanguageVersion.of(17))
    }
}

configurations {
    compileOnly {
        extendsFrom(configurations.annotationProcessor.get())
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation(libs.springBootStarterDataJpa)
    implementation(libs.springBootStarterWeb)
    compileOnly(libs.lombok)
    runtimeOnly(libs.h2)
    annotationProcessor(libs.lombok)
    testImplementation(libs.springBootStarterTest)
    testRuntimeOnly(libs.junitPlatformLauncher)
}

tasks.withType<Test> {
    useJUnitPlatform()
}

It looks cleaner, doesn’t it? We can clearly see that this approach is more maintainable and readable. However, there are a few key points to highlight:

The Gradle Version Catalog offers a structured and organized method for managing versions. It’s important to note that using the Version Catalog doesn’t restrict you to this method alone—you can still directly specify dependency and plugin versions as needed for your project. The Version Catalog simply adds more options and flexibility to your dependency management.

Another significant advantage is the ability to use the Gradle Version Catalog in multi-module projects, which is particularly common in Android development. You can create a shared version catalog for all modules within a project, ensuring consistent versioning and simplifying dependency management across the entire project.

In summary, the Gradle Version Catalog is a powerful tool for managing dependencies. It enhances readability and consistency, centralizes version control, and provides flexibility, making the development process more efficient and reducing the risk of version conflicts.

References