In this chapter, we talk about development techniques, procedures, and tools you can use for the examples in this book and any subsequent projects using Java MVC.
Using Gradle as a Build Framework
Gradle is a modern build framework/build automation tool. It provides for a pure declarative configuration style, but you can also add imperative build code in the form of Groovy (or Kotlin) script snippets, if needed.
Best practices indicate that for build scripts, declarative programming (which tells what a build script has to do, not how it should do it) is favorable over imperative programming (precise step-by-step instructions).
In the rest of this book, we use Gradle for build automation, because it has a very concise build configuration and can be used from the console (the Linux bash and Windows consoles) and from inside IDEs like Eclipse. Gradle build scripts can be as small as just three lines, but they can also contain arbitrarily long code. We will use Gradle as a tool and a little later in this chapter describe more of its characteristics.
If you want to use OpenJDK 8 to build and run applications, you must add a valid cacerts file. Simply install OpenJDK version 10, and then copy the OpenJDK10-INST-DIR/lib/security/cacerts to OpenJDK8-INST-DIR/lib/security/cacerts file.
Using Eclipse as an IDE
Eclipse is an IDE (Integrated Development Environment) with a plethora of functionalities that help to develop Java Enterprise projects. It is freely available and you can use it for both commercial and non-commercial projects without charge.
Eclipse can be extended by plugins, from which many are developed by the community and are free to use. Plugins, however, might also come from vendors and you might have to buy licenses to use them. In this book, we will only use free plugins. If you feel tempted to try proprietary plugins, which under the circumstances might boost your development, visit the Eclipse marketplace at https://marketplace.eclipse.org and consult each plugin.eclipse.orgtevelopment, which under censes to use
Installing Eclipse
Eclipse comes in several variants. To download any of them, go to https://www.eclipse.org/downloads/ or https://www.eclipse.org/downloads/packages/. We will use the Eclipse IDE for Enterprise Java Developers variant in this book.
If you choose to download the installer, you will be asked for the variant. To select the Enterprise variant from the start, click the Download Packages link and choose the Enterprise version on the next page.
In this book, we will use Eclipse version 2020-03, but you might be able to use higher versions. Just keep in mind that if you run into trouble without an obvious solution, downgrading to Eclipse 2020-03 is an option.
The chgrp ... command changes the group ownership and the chmod ... command allows write access for all group members. The usermod ... command adds a particular user to the new group.
You need to be root for these commands. Also note that the usermod command does not affect the currently active window manager session on the PC. You must, for example, restart your system or, depending on your distribution, log out and log in again for that command to take effect.
This makes it easier to switch between different Eclipse versions on your system.
On a Windows system, the installer sets the access rights for you and it is normally possible for any normal user to install plugins . This depends on the Windows version and on your system’s configuration. Corporate environments often have more fine-grained access rights, with normal users who are unable to install plugins and to upgrade, and superusers for administrative purposes. These rights can be configured using Windows access rights management.
Configuring Eclipse
The format of the eclipse.ini file depends on the Eclipse version. Check https://wiki.eclipse.org/Eclipse.ini for the correct syntax. On that site you will also find precise instructions for specifying the Java executable path. The syntax shown here is for Eclipse 2020-03.
Don’t use escaped backslashes, like in C:\path\to\..., as you would expect for Java-related files!
In order to see which version Java Eclipse uses for running (not for building projects!), start Eclipse, then navigate to Help➤About Eclipse IDE➤Installation Details➤Configuration tab. In the pane, find the line that starts with java.runtime.version=....
Adding Java Runtimes
Eclipse itself is a Java application, and in the preceding section, we learned how to tell Eclipse which Java version to choose for its own interests. For the development itself, you have to tell Eclipse which Java version to use for compiling and running the applications it hosts.
To do so, note the paths of all JDK installations you want to use for Eclipse development. Then, start Eclipse.
When you start Eclipse, it asks you for a workspace. This folder can hold several distinct or interrelated projects. It is up to you if you want to choose an existing workspace or prefer to use a fresh new folder for an empty workspace.
Inside Eclipse, go to Window➤Preferences➤Java➤Installed JREs. Usually Eclipse is clever enough to automatically provide the JRE it used for its own startup. If this is enough for you, you don’t have to do anything here. Otherwise, click the Add... button to register more JREs. In the subsequent dialog, select Standard VM as the JRE type.
For Java 8, and other than when the name suggests, you must provide the paths to JDK installations, not JRE installations in the strict sense.
Select the check box to mark your primary JRE. Don’t forget to click the Apply or Apply and Close button to register your changes.
Adding Plugins
Eclipse can be extended by many useful plugins. Some of them are necessary for your development, and some just improve your development workflow. In this book, we won’t use too many extra plugins, and I will provide plugin installation instructions when they are needed.
As an exception, we will now install a Gradle plugin. We will later see that we can use Gradle from the console, but the Gradle plugin in Eclipse allows us to use Gradle directly from inside the IDE. Open Help➤Install New Software... and enter Eclipse Buildship (Gradle) and http://download.eclipse.org/buildship/updates/latest in the dialog. Select all the features and finish the wizard.
Eclipse Everyday Usage
You can get to an identifier’s definition by placing the cursor over it and pressing F3. This works for variables (to navigate to their declarations) and classes/interfaces (to navigate to their definitions). You can even inspect referenced and Java standard library classes that way. Eclipse will download sources and show the code. This is a great way to learn about libraries in-depth by looking at the code.
To rapidly find a resource, such as a file, class, or interface, press Ctrl+Shift+R.
Start typing code and press Ctrl+Space and Eclipse will show you suggestions on how to finish your typing. For example, type new SimpleDa and then press Ctrl+Space. The list provided will contain all the constructors for the SimpleDateFormat class. Even better, you can make that shorter by typing new SiDF and pressing Ctrl+Space, because Eclipse will guess the missing lowercase letters. An additional goody is that you don’t have to write the import statements for classes and interfaces you introduce that way. Eclipse will add the imports for you.
Let Eclipse add the imports for all classes not yet resolved by pressing Shift+Ctrl+O (think of O as “organize imports”).
Format your code by pressing Ctrl+Alt+F. This also works with XML and other file types.
Let Eclipse show you super- and subtypes by pressing F4 over a type designator.
Use F5 to update the Project Explorer view, in case files were added or removed from outside of Eclipse.
With a new Eclipse installation, open the Problems view by choosing Window➤Show View➤Other...➤General➤Problems. This will readily point you to any problems that Eclipse detects (compiler problems, configuration problems, and others).
Open the tasks view from Window➤Show View➤Other...➤General➤Tasks to get a list of all occurrences of “TODO” that you entered in code comments.
In case “TODO” is not fine-grained enough for you, you can add bookmarks by right-clicking the vertical bar anywhere on the left side of the code editor. Bookmarks are then listed in the Bookmarks view.
More About Gradle
With Eclipse and the Gradle plugin at hand, we can improve our knowledge of the Gradle framework. To keep things simple for now, we start with a very simple non-Java MVC project.
You can find the Gradle user manual at https://docs.gradle.org/current/userguide/userguide.html.
A Basic Gradle Project
In order to learn more about Gradle, we build a simple EchoLibrary library with just one class and one method, printing a string to the console. Start Eclipse, and you’ll be asked for a workspace. Choose any folder of your choice.
You may add all example projects from this book to a single workspace called JavaMVCBook to keep things together, but this is up to you.
Go to File➤New➤Other...➤Gradle➤Gradle Project. Choose EchoLibrary as the project name. You can use the default settings for the Gradle project options. Upon completion, the New Project wizard prepares the project and adds a few files to the project that holds the Gradle configuration.
If there is a mismatch, remove the invalid entry by clicking Classpath and then choosing Add Library...➤JRE System Library. Add the version 8 JRE you registered with Eclipse. Then click the Apply and Close button.
Gradle Main Concepts
Gradle has a core, which provides the infrastructure for build-related activities. The activities themselves live in Gradle plugins, which need to be specified in the build file and which run on top of the core. For each project, you can specify which plugins are to be used for Gradle builds. There are plugins for compiling Java classes; for packaging artifacts into ZIP, WAR, or EAR files; for running applications; and for publishing applications into a Maven repository. There are also various analysis plugins, IDE integration plugins, utility plugins, and more. And you can of course develop your own plugins.
Plugins perform tasks. For example, the Java plugin has, among others, a compileJava task for compiling Java classes and a jar task for compressing and gathering several compiled classes.
Each Gradle build consists of an initialization, a configuration, and an execution phase. In the initialization phase, Gradle determines whether the subprojects need to be included win the build. (We talk about subprojects later.) In the configuration phase, Gradle evaluates dependencies and builds a task graph, which contains all the tasks that need to be executed for a build. Configurations on all objects always run with every Gradle build. This is an important point and a common pitfall for beginning Gradle users. It means that for a task execution, the configuration for seemingly totally unrelated tasks is called as well. So, for performance reasons, the configuration for any task should be really fast. A task’s configurations should not do anything that depends on whether the task is actually subject to execution. In the execution phase, the tasks actually do their jobs (compiling, moving, zipping, and so on).
Many Gradle manuals and tutorials at the beginning center around user-defined tasks, which is actually a little bit misleading to the beginning Gradle user. In many, even bigger projects, the corresponding build.gradle file specifies and configures plugins, but hardly ever addresses tasks directly. Tasks are important from a technical point of view, but starting Gradle introductions by talking about the different phases and the plugin architecture leads to a more thorough understanding of Gradle’s functioning.
Standard Gradle Project Layout
If you know the Maven build framework, the layout of the src folder will look familiar to you.
We will learn how to change the project structure in a later section.
The Central Gradle Build File
The Gradle project wizard from Eclipse creates a sample build.gradle file inside the project’s root folder. For any Gradle project, including projects that don’t use Eclipse, this is the central build file. The Eclipse plugin provides a basic build file with some example entries, but you can of course build this file from scratch.
The Eclipse Gradle plugin sometimes has a funny idea about when and where to show the build file. If you can’t find the file in the Project Explorer, open the Gradle Task view and right-click the project, then choose the Open Gradle Build Script option.
A build file usually starts by defining which plugins are to be used, and then configures the plugins. User-defined tasks with operating instructions can also go to the build file, if needed. It is also possible to add Groovy or Kotlin code to existing tasks, which gives you the power to fine-tune plugins according to your needs.
In this book, we show only Groovy code for Gradle build purposes. Groovy is dynamically typed and because of that maybe just a little bit more concise compared to the statically typed Kotlin. Besides, Groovy dedicatedly is a scripting language, so it’s equipped with many utilities for scripting purposes, while Kotlin is a large-scale computer language and a competitor to Java.
Plugins usually have a very precise and reasonable idea about their defaults, so there is not much to configure for your project. For this reason, the build file could be rather small. This convention-over-configuration style is not an invention of Gradle, but Gradle—with its design aiming at elegance-gratefully adopts this idea.
The first three lines plugins { id 'java-library' } specify that we want to use the java-library plugin. The name tells all, we in fact want to build a Java library, but you can learn about the details in the plugins section of the user manual.
The java { sourceCompatibility = JavaVersion.VERSION_1_8; targetCompatibility = JavaVersion.VERSION_1_8 } settings specify the JRE version of our library. Possible values can be looked up in the org.gradle.api.JavaVersion class, but you won’t find anything surprising there (JDK 13 = JavaVersion.VERSION_1_13 and so on).
Gradle uses your operating system’s default JDK to compile classes. You should not use your Gradle project configuration to set the JDK path, because then you’d introduce some unneeded dependency. After all, a JRE 13 can very well handle JRE 8 files and maybe other developers want to use the same build scripts on their own systems. Instead you can change your operating system’s JAVA_HOME environment variable to specify a JDK path prior to Gradle invocations.
The repositories { jcenter() } lines indicate where Gradle will try to load libraries that your project depends on. The jcenter() points to Bintray’s JCenter, but you can also use google() for Android projects and mavenCentral() for Maven Central. Or, you could specify a custom URL, as in repositories { maven { url "http://my.company.com/myRepo" } }, which comes in handy with private or company-owned repositories. See the Gradle manual section called “Declaring Repositories.”
The dependencies section indicates which libraries our project needs. For the EchoLibrary example, we have no dependency to an external library, but for unit tests, which we did not write in this case but could very well be an exercise for the inclined reader, we add a dependency to the JUnit test library.
All other settings—like the position of the source files, how the generated JAR file is named and where it is written to, where to store and cache downloaded dependencies, and so on—are handled by the plugin defaults.
This build file with a handful of settings can now be used to perform various build tasks.
Running Gradle Tasks
Build-related and user-triggered activities in Gradle are called tasks. The main objective of Gradle from a handling perspective is about invoking tasks.
If this is not the case for you, go to Window➤Show View➤Other...➤Gradle to open a Gradle view. The Console view is available from Window➤Show View➤Console.
If you change the project structure, for example by adding, removing, or renaming custom tasks, you must click the Refresh Tasks for All Projects button in the menu (the bent double arrow); otherwise, the view won’t reflect the changes.
In order to run a Gradle task from inside the Gradle Tasks view, you first have to locate it inside the tree. Depending on how precise your idea is where to look inside the tree, you can also use the menu filter to find a task. Once you find it, double-click it to run the task. Diagnostic output, including any error messages, is shown in both the Gradle Executions and the Console views.
For the EchoLibrary example, building a library JAR most probably is the main task. You can find it in the build section. Once you run it, the final JAR is presented in the build/libs folder.
The build folder might be filtered from the Eclipse project view. In this case, if you want to see it, open the project view menu at the small triangle, go to Filters and Customization, and remove the check mark from the Gradle Build Folder entry.
Gradle Tasks Explained
Gradle Tasks
Name | Group | Description |
---|---|---|
help | help | Displays a help message. |
projects | help | Shows the name of the project and lists the names of all subprojects, if applicable. We talk about subprojects later in this chapter. |
tasks | help | Displays the tasks runnable from the project. You have to add the --all options to include tasks from the other group. To see tasks belonging to a certain group, add the --group <groupName> option (for the groupname, use build, build setup, documentation, help, verification, or other). |
dependencies | help | Plugin-independent. Calculates and displays all the dependencies of the project. You can use this to determine which libraries the project depends on, including transitive dependencies (dependencies introduced indirectly, as dependencies of dependencies). |
init | build setup | Adds files necessary for the current directory to serve as a root for Gradle builds. You do this normally only once and at the beginning of a new project. With the Eclipse Gradle plugin and the New Gradle Project wizard, this task is called automatically. This task does not depend on Gradle plugins being activated. |
wrapper | build setup | Adds a Gradle wrapper to the project. Gradle builds can then be performed without Gradle being installed at an operating system level (Java must be installed). With the Eclipse Gradle plugin and the New Gradle Project wizard, this task is called automatically. This task does not depend on Gradle plugins being activated. |
check | verification | A lifecycle task. Abstractly defined in the base plugin and materialized by activated plugins. Depends on test, but may run additional checks. |
test | verification | Runs all unit tests. |
assemble | build | A lifecycle task. Abstractly defined in the base plugin and materialized by activated plugins. Any plugin that produces a distribution or other consumable artifacts is supposed to make the assemble task depend on it. In a custom task, you would write something like assemble.dependsOn( someTask ). Invoking this task bypasses any tests. |
build | build | A lifecycle task. Abstractly defined in the base plugin and materialized by activated plugins. Depends on the check and assemble tasks, and thus performs all tests and then produces a distribution or other consumable artifacts, depending on the activated plugins. |
clean | build | A lifecycle task. Deletes the build directory. You invoke this task if you want to make sure a subsequent build performs all build steps, even those that seemingly could have been reused from previous build operations. You do not normally invoke this task in everyday work, because if properly set up, Gradle should be able to determine which preparatory tasks need to be executed and which do not (because of previous builds). |
classes | build | Any plugin which, somewhere in its build procedures, needs to build Java classes provided in this task. Its responsibility is to create Java classes from the main section (not test classes) of the sources. |
testClasses | build | Similar to the classes task, but handles the test section from the sources. |
jar | build | Assembles a JAR archive containing the classes from the main section. |
ear | build | Only for the EAR plugin. Assembles an EAR archive from the subprojects (web applications and EJBs). |
javadoc | documentation | Generates JavaDoc API documentation for the source code from the main section. |
compileJava | other | Compiles Java source from the main section. |
compileTestJava | other | Compiles Java source from the test section. |
Each plugin’s documentation may also describe more tasks of particular interest for that plugin.
Gradle Plugins
Base: Provides basic tasks and conventions common for most builds.
Java: Any type of Java project.
Java Library: Extends the Java plugin and provides knowledge about the API exposed to consumers.
Java Platform: Does not contain any sources, but describes a set of interrelated libraries that are usually published together.
Application: Implicitly applies the Java plugin and allows for declaring a main class to be used as an application entry point.
WAR: Extends the Java plugin and adds capabilities to build a web application in the form of a WAR file.
EAR: Allows for creating an EAR file.
Maven Publish: Adds capabilities to publish artifacts to a Maven repository.
Ivy Publish: Adds capabilities to publish artifacts to an Ivy repository.
Distribution: Adds functionalities for simplifying artifact distribution.
Java Library Distribution: Adds functionalities for simplifying artifact distribution, with special attention paid to Java libraries.
Checkstyle: Adds checkstyle checks.
PMD: Adds PMD checks.
JaCoCo: Adds JaCoCo checks.
CodeNarc: Adds CodeNarc checks.
Signing: Adds signing capabilities.
Project Report Plugin: Allows for generating a build report.
You can learn more about each plugin by looking into the Gradle user manual, specifically the chapter entitled “Gradle Plugin Reference.”
More About Repositories
mavenCentral()
jcenter()
google()
flatDir { ... }
maven { ... }
Points to a Maven repository given an explicit URL. The precise syntax is
ivy { ... }
Points to an Ivy repository given an explicit URL. The precise syntax is
mavenLocal()
Uses the local Maven cache (usually in HOME-DIR/.m2)
For URLs you specify as repository locations, Gradle also supports the https:, file:, sftp:, and s3: (Amazon s3 services) protocols, or gcs: (Google cloud storage). The first three, and of course the standard http:// protocol, use the standard URL syntax. If needed, the Gradle manual explains more about the syntaxes for s3: and gcs.
This is for basic authentication. For more advanced authentication schemes, see the section called “Declaring Repositories” in the Gradle manual.
More About Dependencies
Dependencies in Gradle center on configurations. A (dependency-related) configuration is a dependency scope, which means it describes a usage scenario. Consider for example that you have one set of dependencies important only for testing, another set of dependencies needed for the internal functioning of some library, and yet another set of dependencies needed for internal functioning and forwarded to clients (because they show up in public method calls). All those are different scopes, or configurations.
Gradle Configurations
Name | Description |
---|---|
implementation | Any dependency needed to compile the main section of the sources can use this configuration. The dependency also will be used at runtime. |
compile | DEPRECATED. To be replaced by implementation. You find this often in blogs and tutorials, so this is added for your information. Use implementation instead. |
compileOnly | Dependency only needed to compile the main section of the sources. During runtime, some kind of container will provide the dependency, so the project is not required to add this kind of dependency to a deliverable artifact. |
runtimeOnly | Dependency not needed for compilation of the main section of the sources, but subject to being added to deliverable artifacts. |
api | Only for the Java Library plugin, identifies a dependency that must be transferred to library clients as well, because types from the dependency show up in public method calls. |
providedCompile | Only for the WAR plugin; same as implementation, but the dependency will not be added to the WAR file. |
providedRuntime | Only for the WAR plugin; same as runtime, but the dependency will not be added to the WAR file. |
deploy | Only for the EAR plugin; add the dependency to the root of the EAR file. |
earlib | Only for the EAR plugin; add the dependency to the lib folder of the EAR file. |
testImplementation | Any dependency needed to compile the test section of the sources can use this configuration. The dependency also will be used at runtime. |
testCompile | DEPRECATED. To be replaced by testImplementation. You find this often in blogs and tutorials, so this is added for your information. Use testImplementation instead. |
testCompileOnly | Similar to compileOnly, but for the test section of the sources. |
testRuntimeOnly | Similar to runtimeOnly, but for the test section of the sources. |
(The noted dependency here is implementation com.sparkjava:spark-core:- 2.8.0.)
Changing the Project Structure
We learned that, by adhering to the default project structure, we don’t have to spend time in configuring the project, telling it where to find sources and resources.
Because all directory settings are specified as lists (seen from [ ... ]), you can also distribute sources and resources over several folders (use commas as separators).
The Gradle Build File Is a Groovy Script
Apart from the suspicious () in jcenter() and the strange mixture of A B and A = B constructs, this file might look like a configuration file with a syntax limited to setting some properties. The truth is much more gloomy, however. In fact, the build.gradle file is a Groovy script, and Groovy is a fully fledged scripting language running on top of a JVM engine.
Although we already stated that, for build definition files, a declarative programming style is preferable over a declarative programming style, it is, under certain circumstances, acceptable to add programming language constructs like conditional statements, switch constructs, loops, and calls to library objects for IO (files and the console), math, streams, date and time, and whatever else you might think of. Also, the { } brackets in the build files actually do not denote blocks, but closures. So the dependencies { } construct is actually a shortcut for dependencies( { } ), and any A B construct in fact is a method call A( B ).
You could now call any task with the extra option -Dadd.math added to see the conditional statement and console output working.
Script Variables
In order for the ${} substitution to work, the double quotation marks are required—this is a Groovy language feature (GString objects). Otherwise in Groovy you can use both single and double quotation marks to denote strings.
Custom Tasks
We can define our own tasks inside the build.gradle file. Because we can use the Groovy language inside the build script, the possibilities are endless here. We can add logging, include non-standard files in archives, perform encryption, deploy artifacts on servers, publish files in a non-standard way, perform timing, invoke extra preparation and cleanup steps, and more.
The group and description settings are both optional; the default for the group is other, and if you omit the description, an empty string will be taken instead. The possible values for group are build, build setup, documentation, help, verification, and other.
To execute a custom task, you do the same thing as you do for built-in tasks or tasks defined by plugins. However, in order for the Eclipse Gradle plugin to be able to see the new task, you first must right-click the project and then choose Gradle➤Refresh Gradle Project. Then you’ll see the new task in the tree view of the Gradle Tasks view and can execute it by double-clicking it.
The instructions inside the main { } are executed during the configuration phase. It is important to know that such instructions are executed unconditionally for all tasks declared! For task-execution matters, you instead put instructions into doFirst { } or doLast { }. Each task has an action list; if you use doFirst, instructions are prepended to the action list, if you use doLast, actions are appended to the action list.
The magic behind that is that any task is directly available by its name inside the build.gradle script. So, if you write build.dependsOn hello, any execution of the build task first leads to executing hello. In hello.dependsOn build, an execution of the hello task first yields a build execution. This way, it is possible to add task dependency relations to existing standard and non-standard tasks.
The Gradle Wrapper
gradlew and gradlew.bat are Gradle startup scripts for Linux and Windows, respectively. The gradle folder contains the standalone Gradle installation.
The Eclipse Gradle plugin does not use these wrapper scripts. Instead, upon starting the first Gradle task, a Gradle daemon from inside USER_HOME/gradle is started. This daemon runs in the background and any Gradle task execution triggered from Eclipse contacts this daemon for the actual build work. This allows for faster task executions.
If Gradle gets invoked from the console, the wrapper is used, and such a daemon process will be started as well. We talk about the console-oriented way of development in the “Developing Using the Console” section.
Multi-Project Builds
Gradle projects can have subprojects. Apart from gathering projects that exhibit some kind of inter-relation, such a hierarchy built of one main project and one or more subprojects also is important for EAR projects, where we typically have one web application, maybe some EJBs, and possibly some libraries.
Of course you can choose different names for the subprojects. Next, create two folders inside the project folder, with names proj1 and proj2 (or whatever names you have chosen). Add an empty build.gradle file to each of the new folders. You can later add any subproject-related build instructions there.
You can read more about multi-project builds in the sections called “Configuring Multi-Project Builds” and “Authoring Multi-Project Builds” in the Gradle user manual. We will use a multi-project in Chapter 9.
Adding a Deploy Task
The tasks create a temporary password file; this is just the GlassFish way of avoiding manual password entry. The "...".execute() creates a process running on the operating system; for the Windows variant, we have to prepend a cmd /c.
We can now perform a deployment or “un-deployment” by invoking the localDeploy or localUndeploy task, respectively. Since we added a dependsOn: build as a task dependency for deployment, it is not necessary to build a deployable artifact; this is done automatically.
Developing Using the Console
Because the Eclipse Gradle plugin installed wrapper scripts inside the project folder, it is therefore possible to do all build-related work from inside a console (bash terminal in Linux, command interpreter in Windows) instead of from the Eclipse GUI. It is a matter of style; using the console, you can avoid having to switch around Eclipse views and collapsing and scrolling trees. Besides, if you have to add task options or arguments, using the console is much more straightforward and faster compared to the GUI. If you don’t have a GUI because you want to do the build on a server, using the console is your only option.
This section covers using the console for Gradle builds. It is possible to freely mix console and GUI triggered builds, so you can use both approaches at the same time.
This assumes that the gradle is in the PATH (in Windows, gradle.bat is in your PATH). Otherwise, you must specify the complete path to the gradle command. For example: C:gradleingradle.bat.
Gradle Command Options
Option | Description |
---|---|
-?, -h, –help | Shows this help message. |
-Dprop=val | Sets a JVM property. You can use System.getProperty("prop") inside the script to read it. |
-Pprop=val | Sets a project property. You can use prop inside the script to directly read it. |
-w, –warn | Adds warning level diagnostic output. |
-i, –info | Adds some info level diagnostic output. |
-d, –debug | Enables debugging messages when something goes wrong. |
-q, –quiet | Shows error level messages only (quiet). |
–offline | Normally libraries referred to in a Java build task are downloaded into a cache. If you want to disable network access, use this option. |
–status | Shows the status of Gradle daemon(s). Normally upon first startup, a background process (daemon) is started to speed up subsequent Gradle calls. Use this to show the status of the daemon(s). |
–stop | Stops the daemon if it is running. |
-v, –version | Shows the version info. |
This shows tasks from the other group (which are normally discarded). If you run ./gradlew help --task <task>, you can view the info (options) about any particular task.
To troubleshoot build script execution performance problems, there is another option called --profile, which will lead to a performance report being added to build/reports/profile.
The output JAR called EchoLibrary.jar is generated inside the build/libs folder.
For simplicity in the rest of the book, we will only show console Gradle commands, and only the Linux variant.
Installing MVC
That is it; the build process will make sure that all libraries are downloaded, and that Java MVC is added to the web application during a ./gradlew build.
Exercises
Exercise 1: True or false? Using imperative programming (step-by-step instructions) is the preferred programming style for build scripts.
Exercise 2: True or false? For imperative code snippets, you can use C++ code inside a Gradle build script.
Exercise 3: True or false? Eclipse uses the same JRE for its own functionalities and for building projects.
Exercise 4: Identify the three phases of a Gradle build process.
Exercise 5: True or false? Using the standard Gradle Java project layout, Java classes go into src/java/main.
Exercise 6: True or false? The Gradle plugins to be used are specified in the settings.gradle file.
Exercise 7: Gradle downloads project dependencies as necessary. True or false? Where to download from is specified in a downloads { } section inside build.gradle.
Exercise 8: Describe what a configuration is in Gradle jargon.
Exercise 9: Using the Eclipse Gradle plugin, create a GraphicsPrimitives Java library with two classes: Circle and Rectangle. Configure it to use JRE 1.8. Adapt all Gradle build configuration files as necessary.
Exercise 10: If you have two custom tasks:
Under which condition is "Hi, I’m A" printed to the console?
Exercise 11: True or false? The Gradle wrapper works only if Gradle is installed on the operating system.
Exercise 12: Describe what needs to be done to let Gradle use the JDK at /opt/jdk8 (or for Windows, at C:jdk8).
Summary
In this chapter, we talked about development techniques, procedures, and tools you can use for the examples in this book and any subsequent projects using Java MVC.
Gradle is a modern build framework/build automation tool. You can use a declarative configuration style, but you can also add imperative build code in the form of Groovy (or Kotlin) script snippets. Best practices indicate that, for build scripts, declarative programming (which says what a build script has to do, not how it should do it) is favorable over imperative programming (precise step-by-step instructions).
Eclipse is an IDE (Integrated Development Environment) with a plethora of functionalities that help to develop Java Enterprise projects. It can be extended by plugins, which add additional functionalities. We use the Eclipse IDE for Enterprise Java Developers variant for this book.
For the book, we need the Eclipse Gradle plugin. Gradle can also be used from the console, but the Gradle plugin in Eclipse allows us to use Gradle directly from inside the IDE. Open Help➤Install New Software and enter Eclipse Buildship (Gradle) and http://download.eclipse.org/buildship/updates/latest in the dialog . Select all features and finish the wizard.
To start a Gradle project inside Eclipse, go to File➤New➤Other...➤Gradle➤Gradle Project.
The main Gradle concepts are as follows. Gradle has a core, which provides the infrastructure for build-related activities. Gradle plugins are specified in the main build file. They run on top of the core and add features to it. Each plugin exhibits build-related activities in form of tasks. Each Gradle build consists of an initialization, a configuration, and an execution phase. In the initialization phase, Gradle determines whether or not subprojects need to be included within the build. In the configuration phase, Gradle evaluates dependencies and builds a task graph that contains all the tasks that need to be executed for a build. Configurations on all objects always run with every Gradle build. During the execution phase, the tasks do their jobs (compiling, moving, zipping, and so on).
The Gradle project wizard from Eclipse creates a sample build configuration build.gradle file inside the project’s root folder. For any Gradle project, including projects that don’t use Eclipse, this is the central build file. The Eclipse plugin provides a basic build file with some example entries.
A build file usually starts by defining which plugins are to be used, and then configures the plugins. User-defined tasks with operating instructions also can go to the build file. Besides, it is possible to add Groovy or Kotlin code to existing tasks, which enables you to fine-tune plugins according to your needs.
Plugins usually have a very precise and reasonable idea about their defaults, so there is probably not much to configure for your project. For this reason, the build file could be rather small. This convention-over-configuration style is not an invention of Gradle, but Gradle gratefully adopts this idea.
The Eclipse Gradle plugin has Gradle Tasks and Gradle Executions views. In addition, diagnostic output goes into the standard Console view. The two Gradle-related views open by default after you install the Gradle plugin.
In order to run a Gradle task from inside the Gradle Tasks view, you first have to locate the task inside the tree. Depending on how precisely you look inside the tree, you can also use the filter from the menu to find a task. Once you find it, double-click it to run the task. Diagnostic output, including any error messages, is shown in the Gradle Executions and Console views.
mavenCentral()
Hardcoded to point to the publicly available Maven repository at https://repo.maven.apache.org/maven2/
jcenter()
Hardcoded to point to the publicly available Maven repository at https://jcenter.bintray.com/
google()
Hardcoded to point to the publicly available Android specific Maven repository at https://maven.google.com/
flatDir { ... }
Points to a folder with libraries. The precise syntax is
flatDir { dirs '/path1/to/folder', '/path2/to/folder', ... }
Does not support meta-information, so if a dependency can be looked up in a flatDir repository and in another repository with meta-information (Maven, Ivy, and so on), the latter has precedence.
maven { ... }
Points to a Maven repository given an explicit URL. The precise syntax is
maven { url "http://repo.mycompany.com/maven2" }
– ivy { ... }
Points to an Ivy repository given an explicit URL. The precise syntax is
ivy { url "http://repo.mycompany.com/ivy" }
mavenLocal()
Uses the local Maven cache (usually in HOME-DIR/.m2).
Dependencies in Gradle center on configurations. A dependency-related configuration is a dependency scope, which means it describes a usage scenario like testing, compiling, provisioning, and so on. Dependency-related configurations are defined by plugins, but there is a common sense about configuration names, and internally configurations also inherit from each other, which leads to configuration name matches between different plugins.
Inside build.gradle, it is possible to add programming language constructs like conditional statements, switch constructs, loops, and calls to library objects for IO (files and the console), math, streams, date and time, and whatever else you might think of. Also, the { } brackets in the build files actually do not denote blocks, but closures. So the dependencies { } construct is actually a shortcut for dependencies( { } ), and any A B construct in fact is a method call A( B ).
In order for the ${} substitution to work, the double quotation marks are required. This is a Groovy language feature (GString objects). Otherwise, in Groovy, you can use both single and double quotation marks to denote strings.
We can define our own tasks inside the build.gradle file. Because we can use the Groovy language inside the build script, the possibilities are endless. We can add logging, include non-standard files in archives, perform encryption, deploy artifacts on servers, publish files in a non-standard way, perform timing, invoke extra preparation and cleanup steps, and more.
The group and description settings are both optional; the default for group is other, and if you omit the description, an empty string will be taken instead. All possible values for group are build, build setup, documentation, help, verification, and other.
The magic behind that is that any task is directly available by its name inside the build.gradle script. So, if you write build.dependsOn hello, any execution of the build task first leads to executing hello. With hello.dependsOn build, an execution of the hello task first yields a build execution. This way, it is possible to add task dependency relations to existing standard and non-standard tasks.
Because the Eclipse Gradle plugin installed wrapper scripts inside the project folder, it is therefore possible to do all build-related work from inside a console (bash terminal in Linux, command interpreter in Windows) instead of from the Eclipse GUI. It is a matter of style; using the console, you can avoid having to switch around Eclipse views and collapsing and scrolling trees. Besides, if you have to add task options or arguments, using the console is much more straightforward and faster compared to the GUI. If you don’t have a GUI because you want to do the build on a server, using the console is your only option.
This assumes that the gradle is in the PATH (in Windows, gradle.bat is in your PATH). Otherwise, you must specify the complete path to the gradle command. For example: C:gradleingradle.bat.
This shows tasks from the other group (which are normally discarded). If you run ./gradlew help --task <task>, you can view the info (options) about any particular task.
In the next chapter, we talk about a clean "Hello World" style project using the development workflow we just described.