Building a Java Web Application with Gradle
Building a Java Web Application with Gradle
by Benjamin Muschko, author of Gradle in Action
Gradle provides a build-by-convention approach for certain problem domains like Java projects by introducing pre-defined project layouts with sensible defaults. In this article, based on chapter 3 of Gradle in Action, author Benjamin Muschko explains how to apply the Java, War and Jetty plugins to build and run your web application with Gradle.
Today’s world is busy. Many of us manage multiple projects simultaneously, both in our professional and private lives. Often times you might find yourself in situations where you feel overwhelmed and out of control. The key to staying organized and focused on priorities is a well-maintained to-do list. Sure, you could always write down your tasks on a piece of paper but wouldn’t it be convenient to be able to access your action items from everywhere you go? Access to the Internet is almost omnipresent, either through your mobile phone or publicly available access points. In Gradle in Action, the illustrative example is a web-based and visually appealing application, shown in figure 1.
Figure 1 The To Do application is accessible through the internet and manages action items in a data store.
Gradle plugins act as enablers to automate these tasks. A plugin extends your project by introducing domain-specific conventions and tasks with sensible defaults. One of the plugins that Gradle ships with is the Java plugin. The Java plugin goes far beyond the basic functionality of source code compilation and packaging. It establishes a standard layout for your project and makes sure that tasks are executed in the correct order so they make sense in the context of a Java project. It’s time to create a build script for our application and apply the Java plugin.
Building Java applications
Every Gradle project starts with the creation of the build script named build.gradle. Create the file and tell your project to use the Java plugin like this:
apply plugin: 'java'
One line of code is enough to build your Java code, but how does Gradle know where to find your source files? One of the conventions the Java plugin introduces is the location of the source code. By default, the plugin searches for production source code in the directory src/main/java.
Building web applications
Gradle also provides extensive support for building web applications through the War plugin. The War plugin extends the Java plugin by adding conventions for web application development and support for assembling WAR files. Let’s also apply the plugin to our project:
apply plugin: 'war'
The default convention for web application sources is the directory src/main/webapp. Suppose you’ve already identified the Java classes required to write this application. With all the production source code and web resource files in the right location your project layout should look like this:
│ └── com
│ └── manning
│ └── gia
│ └── todo
│ ├── model
│ │ └── ToDoItem.java
│ ├── repository
│ │ ├── InMemoryToDoRepository.java
│ │ └── ToDoRepository.java
│ └── web
│ └── ToDoServlet.java
└── webapp #A
│ └── web.xml #B
├── css #C
│ ├── base.css
│ └── bg.png
└── jsp #D
#A Default directory for web application source files
#B Web application descriptor file
#C Directory storing style sheets that describe how to display HTML elements
#D Directory holding dynamic scripting view components in the form of JSPs
Declaring external dependencies
We implemented our web application with the help of classes that are not part of the Java Standard Edition, such javax.servlet.HttpServlet. Before we run the build we will need to make sure that we declare those external dependencies. In the Java world, dependencies are distributed and used in the form of JAR files. Many libraries are available in a repository, such as a file system or central server. Gradle requires you to define at least one repository in order to use a dependency. For our purposes, we are going to use the publicly available, internet-accessible repository Maven Central:
#A Shortcut notation for configuring the central Maven 2 repository accessible under http://repo1.maven.org/maven2
In Gradle, dependencies are grouped by configurations. The configuration we will use for the Servlet dependency is providedCompile. It is used for dependencies that are required for compilation but provided by the runtime environment. Runtime dependencies like the JSTL library are not needed for the compilation process but needed at runtime. They will become part of the WAR file. The following configuration block declares the external libraries we need for our application:
Building the project
We are ready to build the project. One of the tasks the Java plugin adds to your project is named build. The build task compiles your code, runs your tests and assembles the WAR file—all in the correct order. Running the command gradle build should give you an output similar to this:
$ gradle build
:compileTestJava UP-TO-DATE #C
#A Compiles Java production source code
#B Task provided by the War plugin for assembling the WAR file
#C Compiles Java test source files
#D Runs the unit tests
Each line of the output represents an executed task provided by the Java or War plugin. You might notice that some of the tasks are marked with the message UP-TO-DATE. What that means is that the task was skipped. Gradle’s incremental build support automatically identified that no work needed to be done. Especially in large enterprise projects this feature proves to be a real time saver.
On the root level of your project, you will now find a directory named build, which contains all output of our build run including class files, test reports, the assembled WAR file and temporary files like a manifest needed for the archive. Below is the project structure after executing the build:
│ ├── classes
│ │ └── main #A
│ │ └── com
│ │ └── manning
│ │ └── gia
│ │ └── todo
│ │ ├── model
│ │ │ └── ToDoItem.class
│ │ ├── repository
│ │ │ ├── InMemoryToDoRepository.class
│ │ │ └── ToDoRepository.class
│ │ └── web
│ │ ├── ToDoServlet$ToDoListStats.class
│ │ └── ToDoServlet.class
│ ├── dependency-cache
│ ├── libs
│ │ └── todo-webapp.war #B
│ ├── reports
│ │ └── tests
│ │ ├── base-style.css
│ │ ├── css3-pie-1.0beta3.htc
│ │ ├── index.html
│ │ ├── report.js
│ │ └── style.css
│ ├── test-results
│ │ └── binary
│ │ └── test
│ │ └── results.bin
│ └── tmp
│ └── war
│ └── MANIFEST.MF #C
#A Default directory containing compiled Java class files
#B Assembled WAR file
#C Temporary manifest file for use in WAR file
You have seen how to build the WAR file from a web project with a standard structure. Now it’s time to deploy the file to a Servlet container. In the next section we will fire up Jetty to run the application on our local development machine.
Running the application
Running a web application on your local machine should be easy, enable rapid application development (RAD) and provide fast startup times. Optimally, it should not require you to install a web container runtime environment. Jetty is a popular, lightweight Open Source web container supporting all of these features mentioned above. It comes with an embedded implementation by adding an HTTP module to your application. Gradle’s Jetty plugin extends the War plugin, provides tasks for deploying a web application to the embedded container and runs your application. In your build script, use the plugin like this:
apply plugin: 'jetty'
The task we are going to use to run the web application is called jettyRun. It will start the Jetty container without even having to create a WAR file. The output of running the task on the command line should look similar to this:
$ gradle jettyRun
> Building > :jettyRun > Running at http://localhost:8080/todo-webapp-jetty
On the last line of the output, the plugin gives you the URL that Jetty listens for incoming requests. Open your favorite browser and enter the URL. Finally, we can see our To Do web application in action. Figure 2 shows a screenshot of the user interface rendered in the browser.
Figure 2 Web-based user interface of To Do application and its actions
Gradle will leave the application running until you stop it by pressing CTRL + C. How did Jetty know what port and context to use for running the application? Again, it’s conventions. The default port of a web application run by the Jetty plugin is 8080.
You’ve effortlessly implemented a Java web application, built and ran it with Gradle. All it took was a couple of lines of code in your build script as long as you stick to the standard conventions.
Here are some other Manning titles you might be interested in:
Making Java GroovyKenneth Kousen
The Well-Grounded Java DeveloperBenjamin J. Evans and Martijn Verburg
Groovy in Action, Second EditionDierk König, Guillaume Laforge, Paul King, Jon Skeet, and Hamlet D'Arcy