Building a web application with Gradle

duration 15 minutes

Prerequisites:

Learn how to build and test a simple web application using Gradle and Open Liberty.

What you’ll learn

You will learn how to build and test a simple web servlet application using the Gradle war plug-in and the Liberty Gradle plug-in. The war plug-in compiles and builds the application code. The liberty Gradle plug-in installs the Open Liberty runtime, creates an instance, and installs the application to run and test. The application displays a simple web page with a link. When you click that link, the application calls the servlet to return a simple response of Hello! Is Gradle working for you?.

One benefit of using a build tool like Gradle is that you can define the details of the project and any dependencies it has, and Gradle automatically downloads and installs the dependencies. Another benefit of using Gradle is that it can run repeatable, automated tests on the application. You can, of course, test your application manually by starting a Liberty instance and pointing a web browser at the application URL. However, automated tests are a much better approach because you can easily rerun the same tests each time the application is built. If the tests don’t pass after you change the application, the build fails, and you know that you introduced a regression that requires a fix to your code.

Choosing a build tool often comes down to personal or organizational preference, but you might choose to use Gradle for several reasons. Gradle defines its builds by using Groovy build scripts, which gives you a lot of control and customization in your builds. Gradle also uses a build cache that rebuilds only the parts of your application that changed, which saves build time in larger projects. So Gradle can be a good choice in larger, more complex projects.

Using this guide, you will create a Gradle build definition file (build.gradle) for the web application project, and use it to build the application. You will then create a simple, automated test, and configure Gradle to run it after building the application.

Learn more about Gradle on the official Gradle website.

Getting started

The fastest way to work through this guide is to clone the Git repository and use the projects that are provided inside:

git clone https://github.com/openliberty/guide-gradle-intro.git
cd guide-gradle-intro

The start directory contains the starting project that you will build upon.

The finish directory contains the finished project that you will build.

Before you begin, make sure you have all the necessary prerequisites.

Creating the application

The web application that you will build using Gradle and Open Liberty is provided for you in the start directory so that you can focus on learning about Gradle. The application uses the standard Gradle directory structure. Using this directory structure saves you from customizing the build.gradle file later.

All the application source code, including the Open Liberty server.xml configuration file, is in the start/src directory:

└── src
    └── main
        └── java
        └── liberty
            └── config
        └── webapp
            └── WEB-INF

Testing Gradle

If you do not have Gradle installed, make sure that the JAVA_HOME environment variable is set, or that the Java application can run. Running the Gradle Wrapper automatically installs Gradle. To learn more about the Gradle Wrapper, see the Gradle Wrapper documentation.

Run the following commands to navigate to the start directory and verify that Gradle was installed correctly:

cd start
gradlew.bat -v
cd start
./gradlew -v

You should see information about the Gradle installation similar to this example:

------------------------------------------------------------
Gradle 7.6
------------------------------------------------------------

Build time:   2022-11-25 13:35:10 UTC
Revision:     daece9dbc5b79370cc8e4fd6fe4b2cd400e150a8

Kotlin:       1.7.10
Groovy:       3.0.13
Ant:          Apache Ant(TM) version 1.10.11 compiled on July 10 2021
JVM:          11.0.12 (Eclipse OpenJ9 openj9-0.27.0)
OS:           Mac OS X 12.6.3 x86_64

Configure your project

settings.gradle

1rootProject.name = 'GradleSample'

build.gradle

  1// tag::war[]
  2apply plugin: 'war'
  3// end::war[]
  4// tag::liberty[]
  5apply plugin: 'liberty'
  6// end::liberty[]
  7
  8sourceCompatibility = 11
  9targetCompatibility = 11
 10tasks.withType(JavaCompile) {
 11    options.encoding = 'UTF-8'
 12}
 13
 14// configure liberty-gradle-plugin 
 15// tag::buildscript[]
 16buildscript {
 17    repositories {
 18        // tag::buildmaven[]
 19        mavenCentral()
 20        // end::buildmaven[]
 21    }
 22    dependencies {
 23        // tag::liberty-dependency[]
 24        classpath 'io.openliberty.tools:liberty-gradle-plugin:3.9.1'
 25        // end::liberty-dependency[]
 26    }
 27}
 28// end::buildscript[]
 29
 30// tag::repositories[]
 31repositories {
 32    // tag::maven[]
 33    mavenCentral()
 34    // end::maven[]
 35}
 36// end::repositories[]
 37
 38// tag::dependencies[]
 39dependencies {
 40    // provided dependencies
 41    // tag::providedcompile[]
 42    providedCompile 'jakarta.platform:jakarta.jakartaee-api:10.0.0'
 43    providedCompile 'org.eclipse.microprofile:microprofile:6.1'
 44    // end::providedcompile[]
 45
 46    // test dependencies
 47    // tag::testimplementation[]
 48    // tag::junit[]
 49    testImplementation 'org.junit.jupiter:junit-jupiter:5.11.3'
 50    // end::junit[]
 51    // tag::commons[]
 52    testImplementation 'org.apache.httpcomponents.client5:httpclient5:5.4.1'
 53    // end::commons[]
 54    // end::testimplementation[]
 55}
 56// end::dependencies[]
 57
 58// tag::ext[]
 59ext  {
 60    liberty.server.var.'http.port' = '9080'
 61    liberty.server.var.'https.port' = '9443'
 62    liberty.server.var.'app.context.root' = project.name
 63}
 64// end::ext[]
 65
 66// tag::openbrowser[]
 67task openBrowser {
 68    description = 'Open browser to the running application'
 69    doLast {
 70        String port = liberty.server.var.'http.port'
 71        String context = liberty.server.var.'app.context.root'
 72        String URL = "http://localhost:" + port + "/" + context + "/" + "servlet"
 73        java.awt.Desktop.desktop.browse URL.toURI()
 74        java.awt.Desktop.desktop.browse file("$buildDir/reports/tests/test/index.html").toURI()
 75    }
 76}
 77// end::openbrowser[]
 78
 79// tag::tests[]
 80test {
 81    // tag::junitplatform[]
 82    useJUnitPlatform()
 83    // end::junitplatform[]
 84    testLogging {
 85        events 'passed', 'skipped', 'failed', 'standardOut'
 86        exceptionFormat 'full'
 87    }
 88    // tag::systemproperty[]
 89    // tag::httpport[]
 90    systemProperty 'http.port', liberty.server.var.'http.port'
 91    // end::httpport[]
 92    // tag::contextroot[]
 93    systemProperty 'context.root',  liberty.server.var.'app.context.root'
 94    // end::contextroot[]
 95    // end::systemproperty[]
 96}
 97// end::tests[]
 98
 99// tag::depends[]
100test.dependsOn 'libertyStart'
101test.finalizedBy(openBrowser)
102clean.dependsOn 'libertyStop'
103// end::depends[]

The project configuration is defined in the Gradle settings and build files. You will create these project configurations one section at a time.

Gradle settings are used to instantiate and configure the project. This sample uses the settings.gradle to name the project GradleSample.

Create the Gradle settings file in the start directory.
settings.gradle

This settings.gradle file isn’t required for a single-module Gradle project. Without this definition, by default, the project name is set as the name of the folder in which it is contained (start for this example).

Let’s go through the build.gradle file so that you understand each part.

Configuration

Purpose

Plug-ins used

The first part of the build file specifies the plug-ins required to build the project and some basic project configuration.

buildscript

Where to find plug-ins for download.

repositories

Where to find dependencies for download.

dependencies

Java dependencies that are required for compiling, testing, and running the application are included here.

ext

Gradle extra properties extension for project level properties.

test

Unit test and integration test configuration.

Create the build file in the start directory.
build.gradle

The first section of code defines the war and liberty plug-ins that you want to use. The war plug-in contains all the tasks to compile Java files, build the WAR file structure, and assemble the archive. The liberty plug-in contains the tasks used to install the Liberty runtime and create and manage the associated Liberty instances. The compatibility and encoding settings are for Java.

The buildscript section defines plug-in versions to use in the build and where to find them. This guide uses the liberty plug-in, which is available from the Maven Central Repository.

The repositories section defines where to find the dependencies that you are using in the build. For this build, everything you need is in Maven Central.

The dependencies section defines what is needed to compile and test the code. This section also defines how to run the application. The providedCompile dependencies are APIs that are needed to compile the application, but they do not need to be packaged with the application because Open Liberty provides their implementation at run time. The testImplementation dependencies are needed to compile and run tests.

The Gradle extra properties extension allows you to add properties to a Gradle project. If you use a value more than once in your build file, you can simplify updates by defining it as a variable here and referring to the variable later in the build file. This project defines variables for the application ports and the context-root.

You can view the default and Liberty tasks available by running the following command:

gradlew.bat tasks
./gradlew tasks

Running the application

Start Open Liberty in dev mode, which starts the Open Liberty instance and listens for file changes:

./gradlew libertyDev

After you see the following message, your Liberty instance is ready in dev mode.

**********************************************
*    Liberty is running in dev mode.

The dev mode holds your command prompt to listen for file changes. You need to open another command prompt to continue, or simply open the project in your editor.

Navigate your browser to the http://localhost:9080/GradleSample/servlet URL to access the application. The servlet returns a simple response of Hello! Is Gradle working for you?.

Testing the web application

EndpointIT.java

 1// tag::copyright[]
 2/*******************************************************************************
 3 * Copyright (c) 2017, 2024 IBM Corporation and others.
 4 * All rights reserved. This program and the accompanying materials
 5 * are made available under the terms of the Eclipse Public License 2.0
 6 * which accompanies this distribution, and is available at
 7 * http://www.eclipse.org/legal/epl-2.0/
 8 *
 9 * SPDX-License-Identifier: EPL-2.0
10 *******************************************************************************/
11// end::copyright[]
12package io.openliberty.guides.hello.it;
13
14// tag::import[]
15import static org.junit.jupiter.api.Assertions.assertEquals;
16import static org.junit.jupiter.api.Assertions.assertTrue;
17
18import java.io.BufferedReader;
19import java.io.InputStreamReader;
20
21import org.apache.hc.client5.http.classic.methods.HttpGet;
22import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
23import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
24import org.apache.hc.client5.http.impl.classic.HttpClients;
25import org.apache.hc.core5.http.HttpStatus;
26import org.junit.jupiter.api.BeforeAll;
27import org.junit.jupiter.api.Test;
28// end::import[]
29
30// tag::endpointit[]
31public class EndpointIT {
32    private static String webURL;
33
34    @BeforeAll
35    // tag::init[]
36    public static void init() {
37        String port = System.getProperty("http.port");
38        String context = System.getProperty("context.root");
39        webURL = "http://localhost:" + port + "/" + context + "/" + "servlet";
40        System.out.println("URL: " + webURL);
41    }
42    // end::init[]
43
44    // tag::test[]
45    @Test
46    // end::test[]
47    public void testServlet() throws Exception {
48
49        CloseableHttpClient client = HttpClients.createDefault();
50        HttpGet httpGet = new HttpGet(webURL);
51        CloseableHttpResponse response = null;
52
53        // tag::try[]
54        try {
55            response = client.execute(httpGet);
56
57            int statusCode = response.getCode();
58            assertEquals(HttpStatus.SC_OK, statusCode, "HTTP GET failed");
59
60            BufferedReader reader = new BufferedReader(new InputStreamReader(
61                                        response.getEntity().getContent()));
62            String line;
63            StringBuffer buffer = new StringBuffer();
64            while ((line = reader.readLine()) != null) {
65                buffer.append(line);
66            }
67            reader.close();
68            assertTrue(buffer.toString().contains("Hello! Is Gradle working for you?"),
69                "Unexpected response body: " + buffer.toString());
70        } finally {
71            response.close();
72        }
73        // end::try[]
74    }
75}
76//end::endpointit[]

build.gradle

  1// tag::war[]
  2apply plugin: 'war'
  3// end::war[]
  4// tag::liberty[]
  5apply plugin: 'liberty'
  6// end::liberty[]
  7
  8sourceCompatibility = 11
  9targetCompatibility = 11
 10tasks.withType(JavaCompile) {
 11    options.encoding = 'UTF-8'
 12}
 13
 14// configure liberty-gradle-plugin 
 15// tag::buildscript[]
 16buildscript {
 17    repositories {
 18        // tag::buildmaven[]
 19        mavenCentral()
 20        // end::buildmaven[]
 21    }
 22    dependencies {
 23        // tag::liberty-dependency[]
 24        classpath 'io.openliberty.tools:liberty-gradle-plugin:3.9.1'
 25        // end::liberty-dependency[]
 26    }
 27}
 28// end::buildscript[]
 29
 30// tag::repositories[]
 31repositories {
 32    // tag::maven[]
 33    mavenCentral()
 34    // end::maven[]
 35}
 36// end::repositories[]
 37
 38// tag::dependencies[]
 39dependencies {
 40    // provided dependencies
 41    // tag::providedcompile[]
 42    providedCompile 'jakarta.platform:jakarta.jakartaee-api:10.0.0'
 43    providedCompile 'org.eclipse.microprofile:microprofile:6.1'
 44    // end::providedcompile[]
 45
 46    // test dependencies
 47    // tag::testimplementation[]
 48    // tag::junit[]
 49    testImplementation 'org.junit.jupiter:junit-jupiter:5.11.3'
 50    // end::junit[]
 51    // tag::commons[]
 52    testImplementation 'org.apache.httpcomponents.client5:httpclient5:5.4.1'
 53    // end::commons[]
 54    // end::testimplementation[]
 55}
 56// end::dependencies[]
 57
 58// tag::ext[]
 59ext  {
 60    liberty.server.var.'http.port' = '9080'
 61    liberty.server.var.'https.port' = '9443'
 62    liberty.server.var.'app.context.root' = project.name
 63}
 64// end::ext[]
 65
 66// tag::openbrowser[]
 67task openBrowser {
 68    description = 'Open browser to the running application'
 69    doLast {
 70        String port = liberty.server.var.'http.port'
 71        String context = liberty.server.var.'app.context.root'
 72        String URL = "http://localhost:" + port + "/" + context + "/" + "servlet"
 73        java.awt.Desktop.desktop.browse URL.toURI()
 74        java.awt.Desktop.desktop.browse file("$buildDir/reports/tests/test/index.html").toURI()
 75    }
 76}
 77// end::openbrowser[]
 78
 79// tag::tests[]
 80test {
 81    // tag::junitplatform[]
 82    useJUnitPlatform()
 83    // end::junitplatform[]
 84    testLogging {
 85        events 'passed', 'skipped', 'failed', 'standardOut'
 86        exceptionFormat 'full'
 87    }
 88    // tag::systemproperty[]
 89    // tag::httpport[]
 90    systemProperty 'http.port', liberty.server.var.'http.port'
 91    // end::httpport[]
 92    // tag::contextroot[]
 93    systemProperty 'context.root',  liberty.server.var.'app.context.root'
 94    // end::contextroot[]
 95    // end::systemproperty[]
 96}
 97// end::tests[]
 98
 99// tag::depends[]
100test.dependsOn 'libertyStart'
101test.finalizedBy(openBrowser)
102clean.dependsOn 'libertyStop'
103// end::depends[]

HelloServlet.java

 1// tag::copyright[]
 2/*******************************************************************************
 3 * Copyright (c) 2017, 2022 IBM Corporation and others.
 4 * All rights reserved. This program and the accompanying materials
 5 * are made available under the terms of the Eclipse Public License 2.0
 6 * which accompanies this distribution, and is available at
 7 * http://www.eclipse.org/legal/epl-2.0/
 8 *
 9 * SPDX-License-Identifier: EPL-2.0
10 *******************************************************************************/
11// end::copyright[]
12package io.openliberty.guides.hello;
13
14import java.io.IOException;
15
16import jakarta.servlet.ServletException;
17import jakarta.servlet.annotation.WebServlet;
18import jakarta.servlet.http.HttpServlet;
19import jakarta.servlet.http.HttpServletRequest;
20import jakarta.servlet.http.HttpServletResponse;
21
22@WebServlet(urlPatterns = "/servlet")
23public class HelloServlet extends HttpServlet {
24    private static final long serialVersionUID = 1L;
25
26    protected void doGet(HttpServletRequest request, HttpServletResponse response)
27        throws ServletException, IOException {
28        // tag::responsestring[]
29        response.getWriter().append("Hello! Is Gradle working for you?\n");
30        // end::responsestring[]
31    }
32
33    protected void doPost(HttpServletRequest request, HttpServletResponse response)
34        throws ServletException, IOException {
35        doGet(request, response);
36    }
37}

One of the benefits of building an application with a build system like Gradle is that it can be configured to run a set of automated tests. The war plug-in extends the Java plug-in, which provides test tasks. You can write tests for the individual units of code outside of a running Liberty instance (unit tests), or you can write them to call the application that runs on the Liberty instance (integration tests). In this example, you will create a simple integration test that checks that the web page opens and that the correct response is returned when the link is clicked.

Create the EndpointIT test class.
src/test/java/io/openliberty/guides/hello/it/EndpointIT.java

The test class name ends in IT to indicate that it contains an integration test. The integration tests are put in the it folder by convention.

The test section in your build file is added by the Java plug-in, and the useJUnitPlatform() line configures Gradle to add JUnit 5 support.

The systemProperty configuration defines some variables needed by the test class. While the port number and context-root information can be hardcoded in the test class, it is better to specify it in a single place like the Gradle build.gradle file, in case they need to change. The systemProperty lines passes these details to the test JVMs as a series of system properties, resolving the http.port and context.root variables.

The init() method in the EndpointIT.java test class uses these system variables to build the URL of the application.

In the test class, after defining how to build the application URL, the @Test annotation indicates the start of the test method.

In the try block of the test method, an HTTP GET request to the URL of the application returns a status code. If the response to the request includes the string Hello! Is Gradle working for you?, the test passes. If that string is not in the response, the test fails. The HTTP client then disconnects from the application.

In the import statements of this test class, you’ll notice that the test has some new dependencies. Earlier you added some testImplementation dependencies. The Apache httpclient and org.junit.jupiter dependencies are needed to compile and run the integration test EndpointIT class.

The scope for each of the dependencies is set to testImplementation because the libraries are needed only during the Gradle test phase and do not need to be packaged with the application.

Now, the created WAR file contains the web application, and dev mode can run any integration test classes that it finds. Integration test classes are classes with names that end in IT.

The directory structure of the project in the start folder should now look like this example:

└── build.gradle
├── settings.gradle
└── src
    ├── main
    │    ├── java
    │    ├── liberty
    │    │    └── config
    │    └── webapp
    │         └── WEB_INF
    └── test
         └── java

A few more pieces

We show a few more Gradle tricks in this example with the openBrowser task. This task displays your application and the test report in the default browser.

The final Gradle magic to add is the task dependency directives. The dependency directives organizes task execution. In this case, the test task is set to run after the Liberty instance is started, and the openBrowser task is executed after the test task is finalized.

Running the tests

Because you started Open Liberty in dev mode at the start of the guide, press the enter/return key from the command-line session where you started dev mode to run the tests. You will see that the browser opened up the test summary page, which ran one successful test.

To see whether the test detects a failure, change the response string in the src/main/java/io/openliberty/guides/hello/HelloServlet.java file so that it doesn’t match the string that the test is looking for. Then rerun the Gradle test to automatically restart and retest your application to check to see if the test fails.

When you are done checking out the service, exit dev mode by pressing CTRL+C in the command-line session where you ran Liberty.

Great work! You’re done!

You built and tested a web application project running on an Open Liberty instance using Gradle.

Guide Attribution

Building a web application with Gradle by Open Liberty is licensed under CC BY-ND 4.0

Copy file contents
Copied to clipboard

Prerequisites:

Nice work! Where to next?

What did you think of this guide?

Extreme Dislike Dislike Like Extreme Like

What could make this guide better?

Raise an issue to share feedback

Create a pull request to contribute to this guide

Need help?

Ask a question on Stack Overflow

Like Open Liberty? Star our repo on GitHub.

Star