Hi Everyone,
I have been working with Java and Maven for over a decade. Recently, I started migrating many of my projects to Kotlin and Gradle. Most of these projects are multi-module projects with single parent pom.xml for dependency management.
During my research I learned that Gradle provides similar organization of modules with convention plugin. However, there seems to be no direct guide or reference to create a working Spring Boot multi-module project with Gradle convention plugin configuration. The references that I found were pretty useful in demonstrating the core concepts but nothing which could be directly applicable to our use case. This is the reason I decided to write this article.
Project Structure
<PROJECT-ROOT>
|   settings.gradle.kts
|                       
+---buildSrc
|   |   build.gradle.kts
|   |   settings.gradle.kts
|   \---src
|       \---main
|           \---kotlin
|                   dev.all_things.reference.spring-boot-parent.gradle.kts
|                   
\---web-app
    |   build.gradle.kts
    |   
    \---src
        \---main
            +---kotlin
            |   \---config
            |           Application.kt
Convention Plugin Configuration
It refers to a build configuration file which defines set of plugins, dependencies and compiler settings. Each file is a Gradle script with gradle.kts extension. Gradle will expose each configuration as a plugin with file name as identity e.g. dev.all_things.reference.spring-boot-parent.
buildSrc is a special directory where all convention plugin configurations reside. This directory is nothing but a standalone Gradle project with its own independent dependency and repository configuration.
Like any standard Gradle project buildSrc/settings.gradle.kts specifies repositories required for downloading plugings and dependencies.
// Global plugin management
pluginManagement {
    // Project level repositories for plugins
    repositories {
        // Google mirror of Maven Central for optimized performance
        google()
        // Maven Central (primary) plugin repository
        mavenCentral()
        // Gradle plugin repository
        gradlePluginPortal()
    }
}
// Global dependency management
dependencyResolutionManagement {
    /**
     * Project level repositories for dependencies.
     *
     * Gradle uses its own repository by default.
     * Maven repository needs to be explicitly configured.
     */
    repositories {
        // Google mirror of Maven Central for optimized performance
        google()
        // Maven Central (primary) artifact repository
        mavenCentral()
    }
}
buildSrc/build.gradle.kts specifies common dependencies (and corresponding versions) required by the sub-modules.
description = "kotlin-application-parent"
// Convention plugin configuration
plugins {
    // Enables convention definitions in src/main/kotlin
    `kotlin-dsl`
}
// 'buildSrc' specific dependencies
dependencies {
    // Kotlin
    implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.10")
    implementation("org.jetbrains.kotlin:kotlin-allopen:1.9.10")
    // Spring Boot
    implementation("org.springframework.boot:spring-boot-gradle-plugin:3.1.3")
}
Notice that kotlin-dsl is configured as a plugin. This enables Kotlin DSL for creating reusable build configurations.
// Convention plugin configuration
plugins {
    // Enables convention definitions in src/main/kotlin
    `kotlin-dsl`
}
dev.all_things.reference.spring-boot-parent.gradle.kts specifies the actual build configuration that sub-modules can reuse. This file supports all configurations as a standard build.gradle.kts.
// Plugins common for sub-modules
plugins {
    // Spring Boot plugin configuration
    id("org.springframework.boot")
    // Spring Boot dependency management configuration
    id("io.spring.dependency-management")
    // Kotlin compiler plugin for JVM
    kotlin("jvm")
    // Kotlin plugin for Spring
    kotlin("plugin.spring")
}
group = "dev.all_things.reference"
version = "1.0.0-SNAPSHOT"
// Enabled by 'Kotlin' plugin
kotlin {
    // JDK specific toolchain configuration
    jvmToolchain(20)
}
// Dependencies common for sub-modules
dependencies {
    // ..
}
Module Configuration
Now that convention configuration is ready, it can be imported by sub-modules using generated plugin id i.e. dev.all_things.reference.spring-boot-parent in their build.gradle.kts.
plugins {
    // Other module specific plugins
    // ...
    // Spring Boot parent configuration for dependency management
    id("dev.all_things.reference.spring-boot-parent")
}
Conclusion
A project can have multiple convention configurations. Multiple sub-modules in a project can also import one or more such configurations.
Source Code
Keep in Touch
Please follow me on Twitter where I regularly share my experiences with useful tools and frameworks.
 

 
    
Top comments (0)