An alternative to Apache Maven many see Gradle Build Tool as a step forward and a better tool, whilst others would suggest it is very good and powerful but overkill for simple Java build tasks.
If you want a good way to learn Gradle then I would recommend Gradle Build Tool Fundamentals | Pluralsight, which I appreciate is not free but it is good, if you already have access to Pluralsight | THE Technology Skills Platform. An alternative is to just study the documentation and use free resources, in which case head over to Gradle User Manual and look at the official guides.
If you use IntelliJ IDEA then Working with Gradle in IntelliJ IDEA (2021) - YouTube is a great starting point.
One of the conventions that Gradle uses over configuration is the Maven directory layout, which is documented at Maven – Introduction to the Standard Directory Layout.
Fortunately Gradle have produced a series of blog posts explaining how it works.
In addition there is The Gradle Cookbook which is a very useful resource.
The Java Plugin adds several tasks to the Gradle build and uses many of the same conventions as Maven, which is very helpful. Using Convention over Configuration means that if you stick to the conventions, you need very little configuration. It is worth highlighting that it has "child" plugins:
The JaCoCo Plugin is often used with Java development, although it can be a little quirky and not always show the correct level of test coverage. When working with it though, I have found Barfuin / gradle-jacoco-log · GitLab very helpful.
Whilst the Java plugin is a "well known" plugin, that you can easily specify in your build file, other plugins are community ones, which need the full id to be specified and have a version associated with them, they are pulled in from the Gradle - Plugins portal.
One issue that does occur, from time to time, is that Gradle does not fully support the very latest JDK, especially just after that JDK ships. This means you cannot use the latest JDK to run Gradle. However you can use toolchains to run Gradle on Java 11 for example but compile your solution on Java 17. Read Toolchains for JVM projects which explains how to do this.
While working on this I found the following helpful:
gradlew -q javaToolchains
This confirms whether auto detect and auto download are enabled and then lists all known/found JDKs. It is worth looking at the following: org.gradle.java.installations.auto-download
, org.gradle.java.installations.auto-detect
, org.gradle.java.installations.paths
which can all be set in the gradle.properties
file.
The Copy - Gradle DSL Version 6.6 task, implements the CopySpec (Gradle API 6.6) interface and is a very powerful option. One method to look out for is expand, which can replace tokens in files as they are copied.
We have "implementation", which covers both compileOnly and runtimeOnly, although we can use these directly. There is also testImplementation, which also has testCompileOnly and testRuntimeOnly but it does also get everything in implementation.
There are a couple of useful options when running Gradle, adding -q
puts it into quiet mode and -i
gives more info.
It is well worth using gradle.properties
file to specify dependency versions, these can be easily used in the main build script, see Writing Build Scripts for some details on this. This can also be done with a buildscript section but you'll need double quotes for the strings when using them.
The Gradle Wrapper is a good way to execute Gradle and it makes sure, when committed to your version control system, that everyone is using the same version of Gradle. This is important when you are using a build server or running your builds via automated pipelines.
It is easy to use the Gradle Wrapper to upgrade Gradle, which I have done with the following two commands:
./gradlew wrapper --gradle-version=6.6.1
./gradlew --version
I used this to upgrade from Gradle 6.6 to 6.6.1 and it was actually the second command the triggered the download and change.
It is important to start by reading Testing in Java & JVM projects, followed by Testing with JUnit5 Sample.
When working with JUnit it is worth examining Test - Gradle DSL Version 6.6 and specifically the "testLogging" events. If you want better looking output then consider using the community plugin Gradle - Plugin: com.adarshr.test-logger. With jUnit5 we need to add useJUnitPlatform()
in the test block, as well as make a number of other changes.
It is worth adding that you can filter tests, and hence focus on what is needed.
This is a complex and interesting area, and clearly gets worse the more things you add. Howwever, it is a fundamental part of Gradle, so here are some things to note.
implementation
, testImplementation
testRuntimeOnly
etc, these are known as "configurations"gradlew dependencies
- will show all the dependency trees for all configurationsgradlew my-project:dependencies
- this works when you have multiple projects in the build filegradlew dependencies --configuration testRuntimeClasspath
- this shows only the specified configuration, in this case "testRuntimeClasspath"These are Gradle commands I have found useful and used in conjunction with other things found here
gradlew projects
- list all the configured projects in the build file, handy for use with the dependencies optionI wanted to output a variable to check its value, but it was not as easy as I expected. I found three options that worked which are as follows
project.logger.warn("Build Directory: $buildDir")
println("Build Directory: $buildDir")
println "Build Directory: $buildDir"
What caught me out was that I started off with single quotes, which don't expand the variable, you need double quotes for variable expansion, and as you can see the brackets are optional.
Sometimes you don't want your "output" showing at the configuration phase, but you want to show something after a task has finished, in which case you will need to do something like this
myCustomTask { item { ... } doLast { println("This displays, once myCustomTask has finished") } }
There is documentation on this at Build Lifecycle which is helpful.