Gradle
Gradle is an automation tool that can be used to build ๐ญ, test ๐งช, and deploy ๐ your project. It's an alternative created to address problems with other tools such as Maven or Ant.
Gradle uses a domain-specific language (DSL) based on the Groovy programming language for defining build scripts. It's possible to use Kotlin instead of Groovy.
You can download Gradle here. It's only needed to initialize Gradle wrapper which is recommended to use. It allows you to use separate Gradle versions per project and with it, others don't need to install Gradle to build/test/... the project.
$ cd my_project
# generate the "gradle" folder (config + downloader)
# generate gradlew (Unix) gradlew.bat (Windows)
# generate .gradle (gradle binaries)
$ gradle wrapper
$ ./gradlew wrapper --gradle-version 7.2 # change version
โ ๏ธ With Version Control, commit all files aside from .gradle
folder.
Gradle components
Project
For Gradle, a project is an application or a library that we are building. A project may be composed of multiple subprojects.
See also: settings.gradle
.
Build file
The build file is where we define how a project is built. It contains tasks, plugin, and dependencies.
See also: build.gradle
and println "$buildDir"
.
Tasks
A task is a simple action such as "compiling the code".
โก๏ธ Use ./gradlew task
to run the task "task"
.
Plugins
Gradle plugins contain pre-defined tasks and additional features simplifying build file and task creation.
Dependencies
These are the other projects that we need to import to build ours.
Groovy Build file
Add plugins
You can import plugins in the plugins
block at the top.
// idea, java, java-library, maven-publish
// application...
plugins {
id 'xxx'
id 'xxx' version 'xxx'
}
Project metadata
group = 'org.example'
version = '1.0-SNAPSHOT'
description = 'Some description [...]' // optional
Project repositories
repositories {
mavenCentral()
}
Add dependencies
dependencies {
implementation 'xxx' // needed to compile + run
testImplementation 'xxx' // needed for tests
// import 'xxx', but do not import its dependency
implementation ('xxx') {
exclude group: 'org.json', module: 'json'
}
}
Custom tasks
tasks.register('hello_world') {
doFirst {
println 'Hello, World!'
}
doLast {
println 'Bye, World!'
}
}
Gradle for Java
Java plugins
plugins {
id 'java'
}
Java dependencies
You can find dependencies at mvnrepository.
dependencies {
// use JUnit 5
testImplementation platform('org.junit:junit-bom:5.9.1')
testImplementation 'org.junit.jupiter:junit-jupiter'
}
Java Compile Options
Add the block below to set Java compiler and its options.
tasks.withType(JavaCompile).configureEach {
// Compiler options
options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation"
options.encoding = "UTF-8"
// Ask the compiler to target a SDK
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
The xxxCompatibility
attributes do not enforce that the compiler has the target version, e.g., JDK 18 can compile code targeting JDK 17. To enforce the use of JDK 17 when compiling, use:
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
โก๏ธ If you only need to set the encoding, it's simpler to use compileJava.options.encoding = 'UTF-8'
.
Java Tests
test {
useJUnitPlatform() // JUnit5
}
Java folder structure
Gradle separate source
, and tests
. Both have a resources
folder.
-
src/main/java
: your java files -
src/resources/java
: your resources (images/...) -
src/test/java
: your tests -
src/resources/java
: resources only for your tests
You can actually edit them however you want:
sourceSets {
main.java.srcDirs = []
main.java.srcDirs += []
main.resources.srcDirs = []
test.java.srcDirs = []
test.resources.srcDirs = []
}
โ ๏ธ From the code, to access a file that is inside the resources folder, you must use the ClassLoader Utilities, as we would in JAR files.
Java run
You can create a task run
to use ./gradlew run
and ./gradlew run --args="arg1 arg2 arg3"
.
tasks.register('run', JavaExec) {
mainClass = 'org.example.Main' // set yours
classpath = sourceSets.main.runtimeClasspath
}
// optional, set run options
tasks.withType(JavaExec).configureEach {
systemProperty 'file.encoding', 'UTF-8'
}
Generate a jar
Add this to generate a jar with ./gradlew jar
. Replace the org.example.Main
with your Main class.
jar {
from sourceSets.main.output
manifest {
attributes 'Main-Class': 'org.example.Main'
}
}
โก๏ธ The output is usually at build/libs/xxx-version.jar
.
๐ See also: shadow plugin.
gradle.properties
It will allow you to load some variables inside your build.gradle
that are defined in .properties
files.
This is useful for projects that need different versions of plugins or dependencies based on the target. We simply edit gradle.property
.
# gradle.properties
myVariable=value
// build.gradle
print "$myVariable" // will print "value"
You may need to learn a bit about Groovy
/Kotlin
to write modular build files that use your variables.
Saliman plugin
If we often need to edit the configuration, we can use saliman
plugin to easily swap from one .properties
to another.
id("net.saliman.properties") version "1.5.2"
We will declare myVariable
as the one determining which .property
file we will load. You can easily change which file is loaded by changing the variable's value.
# gradle.properties
# load gradle-$myVariable.properties
propertiesPluginEnvironmentNameProperty=myVariable
myVariable=11
Currently, myVariable=11
, so we will load gradle-11.properties
.
Local dependencies
Local project
Assuming the root folder has a folder mylib
with a build.gradle
.
-
settings.gradle
include 'mylib' // load
-
build.gradle
dependencies {
implementation project(':mylib')
}
Local jar
This code can be used to include a local jar:
repositories {
// ...
flatDir { dirs 'libs' }
}
dependencies {
// libs/mylib-1.02.jar
implementation 'com.example.mylib:mylib-1.02'
}
๐ป To-do ๐ป
Stuff that I found, but never read/used yet.
- jitpack
- sourceSets, resourcesSets, access to resources
application {
// if you have a module
mainModule.set('com.module.name')
mainClassName = "com.a.package.Main"
}