Gradle Template
Here are sample configuration files for a multi-project Gradle build. It has the following structure:
project-template/
├── application/
├── build
├── console/
├── gradle/
├── gradle.properties
├── gradlew
├── gradlew.bat
├── readme.md
├── settings.gradle.kts
└── shared/
application
, console
and shared
all represent projects, with their own configuration files.
You can find the source code for this project in the GitLab Public Repository for this course, under sample-code/project-template.
Top-Level (Root)
The project root contains the settings.gradle.kts
file, which defines the overall project structure.
// the name of the project
rootProject.name = "multi-project"
// which projects to include
include("application", "console", "shared")
// a way of tracking version numbers globally
// this ensures that we use the same version of libraries in each project
// not every project will use all of these plugins or libraries
// see individual project configuration files for the actual usage
dependencyResolutionManagement {
versionCatalogs {
create("libs") {
// constants
version("jdk", "17")
version("javafx", "18.0.2")
// https://plugins.gradle.org/
plugin("kotlin-lang", "org.jetbrains.kotlin.jvm").version("1.8.10")
plugin("jlink", "org.beryx.jlink").version("2.26.0")
plugin("javafx", "org.openjfx.javafxplugin").version("0.0.13")
plugin("javamodularity", "org.javamodularity.moduleplugin").version("1.8.12")
// https://mvnrepository.com/
library("kotlin-coroutines", "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4")
library("sqlite", "org.xerial:sqlite-jdbc:3.40.1.0")
library("exposed-core", "org.jetbrains.exposed:exposed-core:0.40.1")
library("exposed-dao", "org.jetbrains.exposed:exposed-dao:0.40.1")
library("exposed-jdbc", "org.jetbrains.exposed:exposed-jdbc:0.40.1")
library("junit-jupiter", "org.junit.jupiter:junit-jupiter:5.9.2")
library("sl4j-api", "org.slf4j:slf4j-api:2.0.6")
library("sl4j-simple", "org.slf4j:slf4j-simple:2.0.6")
}
}
}
It also contains gradle.properties
, which includes project definitions.
kotlin.code.style=official
Gradle wrapper settings
There is a top-level gradle directory, containing the Gradle bootstrap files (the means by which Gradle downloads and installs itself when you run gradlew
). These files are auto-generated by Gradle when you setup the project.
You might want to update the gradle-wrapper.properties
to point to a recent version fo Gradle by changing the distributionURL
line. In this example, we’re specifying Gradle 8.0.2.
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Application project
The Application project contains a single src folder, containing the directory tree, and a single build.gradle.kts
file which includes the configuration for this specific project. This is a JavaFX application, so we should expect to see application-style plugins and dependencies.
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
// notice the syntax for the plugin section uses alias
// this is how we pull in the plugins from the Version Catalog (above)
// e.g. libs.plugins.kotlin.lang inserts the kotlin-lang plugin details.
@Suppress("DSL_SCOPE_VIOLATION")
plugins {
application
alias(libs.plugins.kotlin.lang)
alias(libs.plugins.javamodularity)
alias(libs.plugins.javafx)
alias(libs.plugins.jlink)
}
// used for packaging only
group = "net.codebot"
version = "1.0-SNAPSHOT"
// telling Gradle to put Java and Kotlin output in the same build structure
// required since we have Java files (module-info.java) and Kotlin source
val compileKotlin: KotlinCompile by tasks
val compileJava: JavaCompile by tasks
compileJava.destinationDirectory.set(compileKotlin.destinationDirectory)
// pull all dependencies from here
repositories {
mavenCentral()
}
// libraries that we need, using versions from Version Catalog
// we also want to use the shared/ library, so we need to include it here
dependencies {
implementation(project(":shared"))
implementation(libs.kotlin.coroutines)
testImplementation(libs.junit.jupiter)
}
// fancy way of saying "use JUnit 5"
tasks.test {
useJUnitPlatform()
}
// tell Gradle to use a specific version of the JDK when compiling
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(libs.versions.jdk.get()))
}
}
// application plugin settings
// module name that we've set in the module-info.java
// fully-qualified classname to excecute when you use "gradle run"
application {
mainModule.set("net.codebot.application")
mainClass.set("net.codebot.application.Main")
}
// JavaFX plugin settings
// tell the JavaFX plugin which modules to include
// you may need to add others e.g. javafx.web
javafx {
version = libs.versions.javafx.get()
modules = listOf("javafx.controls", "javafx.graphics")
}
// get around small output bug
// https://stackoverflow.com/questions/74453018/jlink-package-kotlin-in-both-merged-module-and-kotlin-stdlib
jlink {
forceMerge("kotlin")
}
Console Application
The Console application has a similar structure to the Application project, with a single src
folder and a build.gradle.kts
file for this project. This is a console application so it doesn’t need JavaFX support.
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
// notice the syntax for the plugin section uses alias
// this is how we pull in the plugins from the Version Catalog (above)
// e.g. libs.plugins.kotlin.lang inserts the kotlin-lang plugin details.
@Suppress("DSL_SCOPE_VIOLATION")
plugins {
application
alias(libs.plugins.kotlin.lang)
alias(libs.plugins.javamodularity)
}
// used for packaging only
group = "net.codebot"
version = "1.0.0"
// telling Gradle to put Java and Kotlin output in the same build structure
// required since we have Java files (module-info.java) and Kotlin source
val compileKotlin: KotlinCompile by tasks
val compileJava: JavaCompile by tasks
compileJava.destinationDirectory.set(compileKotlin.destinationDirectory)
// pull all dependencies from here
repositories {
mavenCentral()
}
// libraries that we need, using versions from Version Catalog
// we also want to use the shared/ library, so we need to include it here
dependencies {
implementation(project(":shared"))
testImplementation(libs.junit.jupiter)
}
// fancy way of saying "use JUnit 5"
tasks.test {
useJUnitPlatform()
}
// tell Gradle to use a specific version of the JDK when compiling
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(libs.versions.jdk.get()))
}
}
// application plugin settings
// module name that we've set in the module-info.java
// fully-qualified classname to excecute when you use "gradle run"
application {
mainModule.set("net.codebot.console")
mainClass.set("net.codebot.console.MainKt")
}
Shared Project
Finally, the Shared project provides services to both the Application and Console projects. It’s basically a library - not something that we execute directly, but code that we need to pull into the other projects. We keep it in a shared project to avoid code duplication.
Here’s the relevant build.gradle.kts
.
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
// notice the syntax for the plugin section uses alias
// this is how we pull in the plugins from the Version Catalog (above)
// e.g. libs.plugins.kotlin.lang inserts the kotlin-lang plugin details.
@Suppress("DSL_SCOPE_VIOLATION")
plugins {
`java-library`
alias(libs.plugins.kotlin.lang)
alias(libs.plugins.javamodularity)
}
// used for packaging only
group = "net.codebot"
version = "1.0.0"
// telling Gradle to put Java and Kotlin output in the same build structure
// required since we have Java files (module-info.java) and Kotlin source
val compileKotlin: KotlinCompile by tasks
val compileJava: JavaCompile by tasks
compileJava.destinationDirectory.set(compileKotlin.destinationDirectory)
// pull all dependencies from here
repositories {
mavenCentral()
}
// libraries that we need, using versions from Version Catalog
// notice that the shared project needs sqlite and exposed, since
// it manages a database that the other projects use (indirectly).
dependencies {
implementation(libs.sqlite)
implementation(libs.exposed.core)
implementation(libs.exposed.jdbc)
implementation(libs.sl4j.api)
implementation(libs.sl4j.simple)
testImplementation(libs.junit.jupiter)
}
// fancy way of saying "use JUnit 5"
tasks.test {
useJUnitPlatform()
}
// tell Gradle to use a specific version of the JDK when compiling
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(libs.versions.jdk.get()))
}
}
For details on module-setup for each of these projects, refer to packages and modules