Search

Dark theme | Light theme

November 13, 2022

Gradle Goodness: Grouping Version Catalog Dependencies Into Bundles

The version catalog in Gradle is very useful to define a list of dependencies in one single place. In our build script we references dependencies from the version catalog using type safe accessors when we define a dependency for a configuration. Sometimes multiple dependencies belong to each other and are used in combination with each other. In the version catalog we can define bundles of such dependency groups. Instead of referencing each dependency individually we can reference a bundle from the version catalog in our build script. This keeps our build script cleaner and updating a bundle only needs a change in the version catalog.

In the following example version catalog we have several Log4j2 dependencies. We create two bundles that each contain a set of the dependencies for Log4j2:

# File: gradle/libs.versions.toml
[versions]
# We define the log4j2 version for our dependencies.
log4j2 = "2.19.0"

[libraries]
# The api and core modules from log4j2 we need in our project.
# We can use version.ref to refer to version defined in the [versions] section.
log4j2-api = { module = "org.apache.logging.log4j:log4j-api", version.ref = "log4j2" }
log4j2-core = { module = "org.apache.logging.log4j:log4j-core", version.ref = "log4j2" }

# Bridge to have Java Util Logging (JUL) processed by log4j2.
log4j2-jul = { module = "org.apache.logging.log4j:log4j-jul", version.ref = "log4j2" }
# JSON layout following ECS (Elastic Search) standard.
log4j2-ecs-layout = "co.elastic.logging:log4j2-ecs-layout:1.5.0"
# Support async logging for log4j2.
disruptor = "com.lmax:disruptor:3.4.4"

[bundles]
# Bundle with log4j2 dependencies needed to compile.
log4j2-impl = ["log4j2-api", "log4j2-core"]

# Bundle with log4j2 dependencies only needed at runtime.
log4j2-runtime = ["log4j2-jul", "log4j2-ecs-layout", "disruptor"]    

With the version catalog in place we can now reference the bundles from our build script. In the following example build script we use both bundles for the configurations implementation and runtimeOnly:

plugins {
    java
}

repositories {
    mavenCentral()
}

dependencies {
    // Use log4j2-impl bundle from version catalog.
    implementation(libs.bundles.log4j2.impl)

    // Use log4j2-runtime bundle from version catalog.
    runtimeOnly(libs.bundles.log4j2.runtime)
}

Bundles are very useful to define dependencies that are used together. We can reference than multiple dependencies with one bundle reference in our build scripts.

Written with Gradle 7.5.1.