Getting Started With Gradle: Creating a Spring Boot Web Application Project

The traditional way to run a Spring web application on a remote server is to package it into a war file and deploy that file into a servlet container.

Although this method has served us well in the past, managing multiple servlet containers has always been a bit cumbersome.

Spring Boot provides one solution to this problem. It allows us to package our web application into an executable jar file that uses an embedded servlet container.

This blog post describes how we can create a Spring Boot web application project that fulfils the following requirements:

  • Our Spring Boot application must use Thymeleaf as a templating engine.
  • Our Spring Boot application must provide us a way to monitor it.
  • Our Gradle project must have separate source and resource directories for unit and integration tests.

Let's get started.

Additional Reading:

If you are not familiar with Gradle, you should read the following blog post before you continue reading this blog post:

Creating a Java Project

Because we want to create a Java project, we have to apply the Java plugin. We can do this by following these steps:

  1. Apply the Gradle Java plugin.
  2. Set the version of our Java source to 1.8.
  3. Configure Gradle to generate classes for Java 1.8.

Our build.gradle file looks as follows:

apply plugin: 'java'

sourceCompatibility = 1.8
targetCompatibility = 1.8
The Java plugin adds new conventions (e.g. the default directory layout), tasks, and properties into our build. If you want to know more about this, you should read the following blog post:

Let's move on and add integration tests into our Gradle build.

Adding Integration Tests Into Our Gradle Build

We can add integration tests into our Gradle build by using the Gradle TestSets plugin. Because I have already written a blog post that describes how we can use this plugin, I won't describe the configuration of this plugin in this blog post.

After we have fulfilled the requirements specified in this blog post, our build.gradle file looks as follows:

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath(
                'org.unbroken-dome.gradle-plugins:gradle-testsets-plugin:1.0.2'
        )
    }
}

apply plugin: 'java'
apply plugin: 'org.unbroken-dome.test-sets'

sourceCompatibility = 1.8
targetCompatibility = 1.8

testSets {
    integrationTest { dirName = 'integration-test' }
}

project.integrationTest {
    outputs.upToDateWhen { false }
}

check.dependsOn integrationTest
integrationTest.mustRunAfter test

tasks.withType(Test) {
    reports.html.destination = file("${reporting.baseDir}/${name}")
}

Let's move on and add Spring Boot support into our Gradle project.

Adding Spring Boot Support Into Our Gradle Project

We can add Spring Boot support into our Gradle project by using the Spring Boot Gradle plugin. We can use this plugin by following these steps:

  1. Add the Spring Boot Gradle plugin (version 1.2.5.RELEASE) to the classpath of the build script.
  2. Apply the Spring Boot Gradle plugin.

The source code of our build.gradle file looks as follows:

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath(
                'org.springframework.boot:spring-boot-gradle-plugin:1.2.5.RELEASE',
                'org.unbroken-dome.gradle-plugins:gradle-testsets-plugin:1.0.2'
        )
    }
}

apply plugin: 'java'
apply plugin: 'org.unbroken-dome.test-sets'
apply plugin: 'spring-boot'

sourceCompatibility = 1.8
targetCompatibility = 1.8

testSets {
    integrationTest { dirName = 'integration-test' }
}

project.integrationTest {
    outputs.upToDateWhen { false }
}

check.dependsOn integrationTest
integrationTest.mustRunAfter test

tasks.withType(Test) {
    reports.html.destination = file("${reporting.baseDir}/${name}")
}


We don't have to use the Bintray's JCenter Maven repository, but because the Gradle TestSets plugin requires it, the example application of this blog post uses it as well.

Additional Reading:

After we have applied the Spring Boot Gradle plugin, we can

  • Package our application into an executable jar file.
  • Run our application by using the bootRun task.
  • Omit the version information information of Spring Boot dependencies.
  • Package our application into a war file.

Naturally we can also configure the Spring Boot Gradle plugin and customize the tasks that are used to run and package our application.

Let's move on and get the required dependencies with Gradle.

Getting the Required Dependencies

We can get the dependencies of our Spring Boot application by using so called starter POMs. The Spring Boot Reference Guide describes the starter POMs as follows:

Starter POMs are a set of convenient dependency descriptors that you can include in your application. You get a one-stop-shop for all the Spring and related technology that you need, without having to hunt through sample code and copy paste loads of dependency descriptors.

In other words, we have to select the correct starter POMs and add the starter POM dependencies into our Gradle build.

We can get the required dependencies by following these steps:

  1. Ensure that the dependencies are fetched from the central Maven2 repository.
  2. Add the spring-boot-starter-actuator dependency into the compile configuration. We need this dependency because it provides us a way to monitor our application when it is running.
  3. Add the spring-boot-starter-thymeleaf dependency into the compile configuration. We need this dependency because we want to create a web application that uses Thymeleaf as a templating engine.
  4. Add the spring-boot-starter-test dependency into the testCompile configuration. We need this dependency because we want to write both unit and integration tests for our web application.

The source code of our build.gradle file looks as follows:

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath(
                'org.springframework.boot:spring-boot-gradle-plugin:1.2.5.RELEASE',
                'org.unbroken-dome.gradle-plugins:gradle-testsets-plugin:1.0.2'
        )
    }
}

apply plugin: 'java'
apply plugin: 'org.unbroken-dome.test-sets'
apply plugin: 'spring-boot'

sourceCompatibility = 1.8
targetCompatibility = 1.8

repositories {
    mavenCentral()
}
 
dependencies {
    compile(
            'org.springframework.boot:spring-boot-starter-actuator',
            'org.springframework.boot:spring-boot-starter-thymeleaf'
    )
    testCompile('org.springframework.boot:spring-boot-starter-test')
}

testSets {
    integrationTest { dirName = 'integration-test' }
}

project.integrationTest {
    outputs.upToDateWhen { false }
}

check.dependsOn integrationTest
integrationTest.mustRunAfter test

tasks.withType(Test) {
    reports.html.destination = file("${reporting.baseDir}/${name}")
}


We don't have to set the versions of the Spring Boot dependencies because the version of the Spring Boot Gradle plugin determines the versions of these dependencies. In other words, we can select the preferred Spring Boot version by setting the version of the Spring Boot Gradle plugin.

Additional Reading:

Let's move on and find out how we can run our Spring Boot application.

Running Our Spring Boot Application

We can run our Spring Boot application by using one of the following methods:

First, we can run our application without creating a jar file by using the bootRun task of the Spring Boot Gradle plugin. We should use this method during the development phase because it makes our static classpath resources (i.e. files found from the src/main/resources directory) reloadable.

In other words, if we use this method, we can make changes to these files when our Spring Boot application is running, and we can see these changes without restarting our application.

We can use this method by running the following command at the command prompt:

gradle clean bootRun

Second, we can package our application into an executable jar file and run the created jar file. We should use this method when we want to run our Spring Boot application on a remote server.

We can create an executable jar file by running the following command at the command prompt:

gradle clean build

This command creates the spring-boot-web-application.jar file to the build/libs directory. After we have copied this jar file to the remote server, we can start our application by running the following command at the command prompt:

java -jar spring-boot-web-application.jar

Let's move on and summarize what we learned from this blog post.

Summary

This blog post has taught us four things:

  • We can add Spring Boot support into our Gradle project by applying the Spring Boot Gradle plugin.
  • We can select the preferred Spring Boot version by setting the version of the Spring Boot Gradle plugin. This means that we don't have to set the dependency versions of the Spring Boot dependencies.
  • If we want to run our Spring Boot application in a development environment, we should use the bootRun task of the Spring Boot Gradle plugin.
  • If we want to run our Spring Boot application on a remote server, we should package it into an executable jar file, copy that jar file to the remote server, and run it.

P.S. You can get the example application of this blog post from Github.

If you want to learn how to use Gradle, you should take a look at my Gradle tutorial.
13 comments… add one
  • Kevin Aug 19, 2015 @ 15:38

    You could also use the site start.spring.io and with a few clicks you have a starting codebase with gradle, thymeleaf and actuator and so much more...

    • Petri Aug 19, 2015 @ 15:51

      Hi Kevin,

      The start.spring.io is indeed a great place to get started (if you know what you are doing). I might be a bit old fashioned, but I want to know how things work before I use them.

  • Mahadev Shinde Apr 6, 2016 @ 19:02

    I always refer your blogs for developement.

    • Petri Apr 7, 2016 @ 17:38

      Thank you for your kind words. I really appreciate them.

  • Felipe Carvalho May 3, 2016 @ 14:53

    Hey, Petri, nice post!

    One remark, though: I'm pretty sure actuator plugin is included by default with spring boot, you don't actually need to declare it as a dependency.

    Btw, why did you chose to declare thymeleaf dependency? Just for didatics? It seemed to me that you didn't actually need it to run a sample spring boot app, is that correct?

    Cheers!

    • Petri Jun 1, 2016 @ 21:42

      Hi Felipe,

      Thank you for kind words. I really appreciate them!

      One remark, though: I’m pretty sure actuator plugin is included by default with spring boot, you don’t actually need to declare it as a dependency.

      I took a quick look at the reference manual of Spring Boot 1.3.X, and it says that:

      The spring-boot-actuator module provides all of Spring Boot’s production-ready features. The simplest way to enable the features is to add a dependency to the spring-boot-starter-actuator ‘Starter POM’.

      I think that this is a pretty good practice because some people might not want that the actuator is enabled by default.

      Btw, why did you chose to declare thymeleaf dependency? Just for didatics? It seemed to me that you didn’t actually need it to run a sample spring boot app, is that correct?

      I simply wanted see how simple it is to create a web application that uses Thymeleaf, and the example actually has one Thymeleaf template.

  • Dan Murphy May 31, 2017 @ 7:40

    Petri, something seems to have changed since this tutorial was written. Your code base in git now consistently fails to build, apparently due to some implicit exclusion rule processing problem.

    From 'gradle --info bootRun':
    ...
    Putting task artifact state for task ':compileJava' into context took 0.0 secs.
    Task :compileJava class loader hash: 41621835a1ddfd325406e64eb3109d65
    Task :compileJava actions class loader hashes: [e8f4c8702fd7b8841599c3c47e651d9a, 750e1d72030581ace81f7325929812f4, 41621835a1ddfd325406e64eb3109d65]
    Adding implicit managed exclusion rules to starter DefaultExternalModuleDependency{group='org.springframework.boot', name='spring-boot-starter-actuator', version='null', configuration='default'}
    :compileJava FAILED
    :compileJava (Thread[Daemon worker Thread 2,5,main]) completed. Took 0.004 secs.

    FAILURE: Build failed with an exception.

    * What went wrong:
    java.lang.UnsupportedOperationException (no error message)

    * Try:
    Run with --stacktrace option to get the stack trace. Run with --debug option to get more log output.

    BUILD FAILED

    Total time: 0.905 secs
    Stopped 0 worker daemon(s).
    Received result Failure[value=org.gradle.initialization.ReportedException: org.gradle.internal.exceptions.LocationAwareException] from daemon DaemonInfo{pid=64619, address=[a9a23b64-87f4-4859-8dc8-a95a459fe47d port:50381, addresses:[/0:0:0:0:0:0:0:1, /127.0.0.1]], state=Idle, lastBusy=1496205187009, context=DefaultDaemonContext[uid=2dbef968-4e8c-4d15-8eda-43bc6d799cff,javaHome=/Library/Java/JavaVirtualMachines/jdk1.8.0_91.jdk/Contents/Home,daemonRegistryDir=/Users/murphstein/.gradle/daemon,pid=64619,idleTimeout=10800000,daemonOpts=-XX:MaxPermSize=256m,-XX:+HeapDumpOnOutOfMemoryError,-Xmx1024m,-Dfile.encoding=UTF-8,-Duser.country=US,-Duser.language=en,-Duser.variant]} (build should be done).

    • Petri May 31, 2017 @ 20:17

      Hi,

      It seems that the Spring Boot Gradle plugin that is used by the example application is so old that it doesn't work with newer Gradle versions anymore. When I updated the version of that plugin to: 1.5.3.RELEASE, everything started to work again. Also, it seems that plugin id: spring-boot is deprecated => use org.springframework.boot instead of the deprecated plugin id.

  • Yi Mar 11, 2018 @ 20:30

    As always, I enjoyed your blog. Just one point, with current version of testsets plugin (1.4.3), the report directory setup for integrationTest in build.gradle appears to be no longer needed.

  • Arnab Nov 16, 2019 @ 11:18

    I am getting this error even after upgrading to 1.5.3.RELEASE
    Execution failed for task ':findMainClass'.
    > org.gradle.api.tasks.SourceSetOutput.getClassesDir()Ljava/io/File;

    • Petri Nov 22, 2019 @ 20:32

      I have to admit that I haven't tested this build script for a very long time. That being said, I assume that the problem has got something to do with the Gradle TestSets plugin. Have you tried to upgrade it to the version 2.2.1?

Leave a Reply