Gradle Basics

Gradle is a build automation tool for multi-language software development. It controls the development process in the tasks of compilation and packaging to testing, deployment, and publishing.

In this post, I will introduce the basic use of Gradle. This post is based on Gradle 8.6 and Kotlin DSL.

Initialize a Gradle Project

You can run the following commands to initialize a Java project with Gradle:

$ gradle init --use-defaults --type java-application

or

$ gradle init \
--type java-application \
--dsl kotlin \
--test-framework junit-jupiter \
--package my.project \
--project-name my-project \
--no-split-project \
--java-version 21

If you wan to create a Spring Boot application, you can use spring initializr.

Configurations

There are two configuration files in Gradle: build.gradle and settings.gradle. They are both important configuration files in a Gradle project, but they serve different purposes.

build.gradle is a script file that defines the configuration of a project. It’s written in the Groovy or Kotlin programming languages, and it specifies how tasks are executed, dependencies are managed, and artifacts are built. This file typically resides in the root directory of your project.

settings.gradle is focused on configuring the structure of a multi-project build and managing the relationships between different projects within it.

Plugins

You can add plugins to configuration file build.gradle.kts like this:

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

Gradle core plugins:

  • java: Provides support for building any type of Java project.
  • application: Provides support for building JVM-based, runnable applications.

Spring Boot plugins:

  • org.springframework.boot: Spring Boot Gradle Plugin
  • io.spring.dependency-management: A Gradle plugin that provides Maven-like dependency management functionality. It will control the versions of your project’s direct and transitive dependencies.

More plugins:

Setting Properties

The following properties are the common properties for Java projects.

group = "com.example"
version = "0.0.1-SNAPSHOT"
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
// or
java {
sourceCompatibility = "21" // JavaVersion.VERSION_21
targetCompatibility = "21"
}
application {
mainClass = "com.example.Main"
}

Repositories

A Repository is a source for 3rd party libraries.

repositories {
mavenCentral()
}

Declare dependencies

You can declare dependencies in build.gradle.kts like this

dependencies {
// Compile dependency
compileOnly('org.projectlombok:lombok:1.18.30')

// Implementation dependency
implementation("joda-time:joda-time:2.2")
implementation("org.springframework.boot:spring-boot-starter-web")

// Runtime dependency
runtimeOnly("com.mysql:mysql-connector-j")

// Test dependency
testImplementation("junit:junit:4.12")
testImplementation("org.springframework.boot:spring-boot-starter-test")
}

In Gradle, dependencies can be classified into several types based on where they come from and how they are managed. Here are the main dependency types:

  1. Compile Dependencies:
    1. These are dependencies required for compiling and building your project. They typically include libraries and frameworks that your code directly depends on to compile successfully.
    2. Dependencies declared with compile are visible to all modules, including downstream consumers. This means that If Module A has a compile dependency on a library, and Module B depends on Module A, then Module B also has access to that library transitively. However, this also exposes the implementation details of Module A to Module B, potentially causing coupling between modules. In Gradle 3.4 and later, compile is deprecated in favor of implementation.
  2. Implementation Dependencies:
    1. Introduced in Gradle 3.4, these dependencies are similar to compile dependencies but have a more restricted visibility.
    2. They are not exposed to downstream consumers of your library or module. This allows for better encapsulation and prevents leaking implementation details. This means that if Module A has an implementation dependency on a library, Module B, depending on Module A, does not have access to that library transitively. This enhances encapsulation and modularity by hiding implementation details of a module from its consumers. It allows for better dependency management and reduces coupling between modules in multi-module projects.
  3. Runtime Dependencies: Dependencies that are only required at runtime, not for compilation. They are needed to execute your application but not to build it.
  4. Test Dependencies: Dependencies required for testing your code. These include testing frameworks, libraries, and utilities used in unit tests, integration tests, or other testing scenarios.
  5. Optional Dependencies: Dependencies that are not strictly required for your project to function but are nice to have. Gradle does not include optional dependencies by default, but you can specify them if needed.

Tasks

tasks.withType<Test> {
useJUnitPlatform()
}

Run Tasks

To list all the available tasks in the project:

$ gradle tasks

Build Java

Before building a Java project, ensure that the java plugin is added to the configuration file build.gradle.kts.

plugins {
java
}

Running the following command to build the project

$ gradle build

Run Java main class

To run a Java project, ensure that the application plugin and the mainClass configuration are added to the configuration file build.gradle.kts. The application plugin makes code runnable.

plugins {
// Apply the application plugin to add support for building a CLI application in Java.
application
}

application {
// Define the main class for the application.
mainClass = "org.example.App"
}

Running the following command to run the main method of a Java project:

$ gradle run

Gradle Wrapper

The Gradle Wrapper is the preferred way of starting a Gradle build. It consists of a batch script for Windows and a shell script for OS X and Linux. These scripts allow you to run a Gradle build without requiring that Gradle be installed on your system.

The Wrapper is a script that invokes a declared version of Gradle, downloading it beforehand if necessary. As a result, developers can get up and running with a Gradle project quickly.

Gradle Wrapper files:

  • gradle/wrapper/gradle-wrapper.jar: The Wrapper JAR file containing code for downloading the Gradle distribution.
  • gradle/wrapper/gradle-wrapper.properties: A properties file responsible for configuring the Wrapper runtime behavior e.g. the Gradle version compatible with this version.
  • gradlew, gradlew.bat: A shell script and a Windows batch script for executing the build with the Wrapper.

If the project you are working on does not contain those Wrapper files, you can generate them.

$ gradle wrapper

Run tasks with gradlew:

$ ./gradlew tasks
$ ./gradlew build
$ ./gradlew run
$ ./gradlew test

References

[1] Building Java Projects with Gradle

[2] Part 1: Initializing the Project

[3] Build Init Plugin

[4] Gradle Wrapper Reference

[5] Spring Boot Gradle Plugin Reference Guide