Gradle

Gradle is an open-source build automation tool focused on flexibility and performance.

Fundamentally, all build systems have a straightforward purpose: they transform the source code written by engineers into executable binaries that can be read by machines. For years, builds had the simple requirements of compiling and packaging soft- ware. But the landscape of modern software development has changed, and so have the needs for build automation.

It is highly recommended reading the Gradle User Manual. In this book, we only focus on one of most important features of Gradle, dependency management.

Dependency management overview

There is a well-known saying in software engineering: Don't reinvent wheels. Nowadays, no one would create a software from scratch, and she must use some third libraries to complete her task without re-writing every line of code on her own. For example, when you want to connect to MySQL, you have to use the database driver as a dependency.

In Java, Maven and Gradle are widely used to help programmers to manage third libraries without manual workload. In this tutorial, we focus on Gradle. Gradle's dependencies are put inside dependencies. For example, in the build.gradle of a template Java EE project:

dependencies {
    compileOnly('javax.servlet:javax.servlet-api:4.0.1')

    testImplementation("org.junit.jupiter:junit-jupiter-api:${junitVersion}")
    testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${junitVersion}")
}

Clearly, your Java web project depends on servlet if JDK is compiling your source code. Here we are using the string notation to declare such dependency. Let's try to decouple the long string javax.servlet:javax.servlet-api:4.0.1, which contains three parts:

  • Group name: javax.servlet. Who develops it.
  • Artifact name: javax.servlet-api. What its name is.
  • Version: 4.0.1. Which version it is.

Those three parts (coordinates) can identify a unique package, and then Gradle is able to download this package from remote server. By default, this remote server is maven central repository. Alternatively, you can also declare a dependency with map notation:

compileOnly group: 'javax.servlet', name: 'javax.servlet-api', version: '4.0.1'

So, what does compileOnly means? Well, compileOnly is one of the dependency scopes. As its name implies, this package is only required during compilation, but not runtime. This is because the container (e.g., Tomcat) will provide necessary dependencies for your web project during runtime. In daily programming, implementation and runtimeOnly are often used[1]. Compared with compileOnly, the main difference can be summarized:

  • compileOnly: put the dependency on the compile classpath only
  • runtimeOnly: put the dependency on the runtime classpath only
  • implementation: put the dependency on both classpaths

Similarly, both testImplementation and testRuntimeOnly are scopes related with tests.

How to find the dependency

We recommend https://search.maven.org/ and https://mvnrepository.com/. Both websites support searching by group and/or artifact names. For example, if you would like to use Gson in you project to handle JSON, you could get the dependency after a quick searching:

Figure A.10 Gson in maven repository.

By the way, in China mainland, there may be some network issues accessing maven central repository. If so, you can use the mirror site of AliYun by replacing repositories of build.gradle with the following:

repositories {
    maven { url 'https://maven.aliyun.com/repository/public/' }
    mavenLocal()
    mavenCentral()
}

[1] provided is deprecated, while api is similar to, but different with implementation. But implementation is the most common in daily programming. See more at Gradle Implementation vs API configuration.