© Peter Späth 2021
P. SpäthBeginning Java MVC 1.0https://doi.org/10.1007/978-1-4842-6280-1_3

3. Development Workflow

Peter Späth1 
(1)
Leipzig, Sachsen, Germany
 

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.

Note

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.

Caution

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.

Note

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.

Use any installation folder suitable for your needs. Plugin installations and version upgrades go in the folder you choose, so ensure appropriate file access rights. On my Linux box, I usually put Eclipse in a folder called:
/opt/eclipse-2019-09
(Or whatever version you have.) Then I make it writable to my Linux user:
cd /opt
USER=...   # enter user name here
GROUP=... # enter group name here
chown -R $USER.$GROUP eclipse-2019-09
This changes the ownership of all files of the Eclipse installation, which makes sense for a one-user workstation. If instead you have different users for Eclipse, you can create a new group called eclipse and give that group write access:
cd /opt
groupadd eclipse
chgrp -R eclipse eclipse-2019-09
chmod -R g+w eclipse-2019-09
USER=...   # enter your username here
usermod -a -G eclipse $USER

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.

Note

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.

As a last step, you can provide a symbolic link to the Eclipse installation folder:
cd /opt
ln -s eclipse-2019-09 eclipse

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

Upon startup, Eclipse uses the default Java version installed on your system. In case it cannot find it or you have several Java versions installed, you can explicitly tell Eclipse which Java to choose. For this aim, open this file
ECLIPSE-INST/eclipse.ini
And add two lines:
-vm
/path/to/your/jdk/bin/java
Directly above the -vmargs line:
...
openFile
--launcher.appendVmargs
-vm
/path/to/your/jdk/bin/java
-vmargs
...
Note

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.

On Windows PCs, you specify the path as follows:
...
-vm C:path oyourjdkinjavaw
...

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.

Note

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.

Note

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

Eclipse provides a lot of functions and you can learn about them by opening the built-in help. To give you a starting point, the following are tips that help you get the most out of Eclipse:
  • 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.

Note

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.

Note

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.

The next thing we do is make sure the project can use an existing JSE installation. The Gradle project wizard might try to use a nonexistent JRE and an error marker will appear. See Figure 3-1.
../images/499016_1_En_3_Chapter/499016_1_En_3_Fig1_HTML.jpg
Figure 3-1

Project error marker (red exclamation mark)

To fix such a mismatch or to check whether the correct JRE is used, right-click the project, then choose Properties➤Java Build Path➤Libraries. See Figure 3-2.
../images/499016_1_En_3_Chapter/499016_1_En_3_Fig2_HTML.jpg
Figure 3-2

JRE mismatch

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.

Next, add a package called book.javamvc.echo by right-clicking src/main/-java➤New➤Package. Inside the package, add an Echo class with these contents:
package book.javamvc.echo;
public class Echo {
    public void echo(String msg) {
        System.out.println(msg);
    }
}

Gradle Main Concepts

By default, Gradle uses one central build file named build.gradle inside the root folder of the project. Before we start talking about this file, we first need to cover Gradle’s 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).

Note

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

The project layout that all Gradle plugins by default expect is as follows:
src
  |- main
  |     |- java
  |     |     |- <java source files>
  |     |- resources
  |           |- <resource files>
  |
  |- test
        |- java
        |     |- <java source files>
        |- resources
              |- <resource files>
build
  |- <any files built by Gradle>
build.gradle       <Gradle build file>
settings.gradle    <(Sub-)Project settings>
gradle.properties  <optional project properties>
Note

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.

Caution

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.

Note

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.

Back to the EchoLibrary sample project. We dismiss the sample build.gradle file created by the wizard and overwrite its contents with the following:
// The EchoLibrary build file
plugins {
    id 'java-library'
}
java {
    sourceCompatibility = JavaVersion.VERSION_1_8
    targetCompatibility = JavaVersion.VERSION_1_8
}
repositories {
    jcenter()
}
dependencies {
    testImplementation 'junit:junit:4.12'
}

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).

Note

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.

The Eclipse Gradle plugin has a Gradle Tasks and a Gradle Executions view. In addition, diagnostic output goes to the standard Console view. The two Gradle-related views open by default after you install the Gradle plugin. See Figure 3-3.
../images/499016_1_En_3_Chapter/499016_1_En_3_Fig3_HTML.jpg
Figure 3-3

Gradle views

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.

The Gradle Tasks view lists all available tasks in a tree view; see Figure 3-4. The scope of the tasks shown can be filtered using the view menu (small down triangle in the menu). If you introduce any custom tasks, this is a good time to enable the Show All Tasks item; otherwise, the custom tasks don’t show up in the list. See Figure 3-5.
../images/499016_1_En_3_Chapter/499016_1_En_3_Fig4_HTML.jpg
Figure 3-4

Gradle tasks view tree

../images/499016_1_En_3_Chapter/499016_1_En_3_Fig5_HTML.jpg
Figure 3-5

Gradle tasks view menu

Caution

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.

Tasks might have option parameters that control their functioning. For example, there is a tasks task that lists only a certain subset of all tasks. More precisely, tasks have a group property, and one of the groups is called other. If you run the tasks task without a parameter, tasks belonging to the other group are not included in the output. To show all tasks using that command, you must add an --all parameter. To do so from Eclipse, go to Run➤Run Configurations, navigate to Gradle Task, and add a new entry, as shown in Figure 3-6 (click the Add button twice to enter tasks and --all). Click Run and switch to the Console view to see the output.
../images/499016_1_En_3_Chapter/499016_1_En_3_Fig6_HTML.jpg
Figure 3-6

Custom Gradle task run configuration

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.

Caution

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

Tasks get defined by plugins, and plugins also might amend or overwrite tasks defined by other plugins, so there is no one-to-one relationship between tasks and plugins. In addition there are plugin-independent tasks defined by Gradle itself. Table 3-1 defines most of the tasks you’ll normally use in your Java projects.
Table 3-1

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

If you’re developing for Java MVC and other Java and JEE/Jakarta EE related projects, the following list shows you the plugins you will most often encounter:
  • 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

Gradle loads libraries from a repository if it determines that the project refers to such libraries. You specify repositories in a repositories { } section inside build.gradle:
repositories {
    repoSpec1 (repository specification, see below)
    repoSpec2
    ...
}
You can use the following as repository specifications:
  • 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', ... }. It 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)

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.

If you need to provide credentials for connecting to a repository, you can specify them in a credentials { } section:
repositories {
    maven {
        url "http://repo.mycompany.com/maven2"
        credentials {
            username "user"
            password "password"
        }
    }
}

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.

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. Table 3-2 list the configurations you’ll often encounter in Java-related projects.
Table 3-2

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.

Once you identify the configurations you need, you specify a list in the dependencies { } section of your build.gradle file:
dependencies {
   implementation 'org.apache.commons:commons-math3:3.6.1'
   // This is the same:
   implementation group:'org.apache.commons',
        name:'commons-math3',
        version:'3.6.1'
   // You can combine:
   implementation 'org.apache.commons:commons-math3:3.6.1',
       'org.apache.commons:commons-lang3:3.10'
   // or like that:
   implementation(
        [ group:'org.apache.commons',
          name:'commons-math3', version:'3.6.1' ],
        [ group:'org.apache.commons',
          name:'commons-lang3', version:'3.10' ]
   )
   // or like that:
   implementation 'org.apache.commons:commons-math3:3.6.1'
   implementation 'org.apache.commons:commons-lang3:3.10'
   testImplementation 'junit:junit:4.12'
}
Normally any indirect dependency, which comes from dependencies of dependencies, gets resolved automatically. Such dependencies are called transitive dependencies. So if you declare a dependency on some library A, which in turn depends on libraries B and C, Gradle will take care of including B and C in the build, without needing to explicitly declare the dependencies on B and C in build.gradle. If you want to prevent Gradle from including transitive dependencies, you can mark them using transitive = false:
dependencies {
    implementation (group: 'org.eclipse.jetty',
                    name: 'jetty-webapp',
                    version: '9.4.28.v20200408') {
        transitive = false
    }
}
You can investigate such transitive dependencies if you invoke the dependencies task. The output will be a tree-like representation of dependencies and transitive dependencies, as for example, in the following:
...
runtimeClasspath - Runtime classpath of source set 'main'.
--- com.sparkjava:spark-core:2.8.0
    +--- org.slf4j:slf4j-api:1.7.25
    +--- org.eclipse.jetty:jetty-server:9.4.12
    |   +--- javax.servlet:javax.servlet-api:3.1.0
    |   +--- org.eclipse.jetty:jetty-http:9.4.12
    |   |   +--- org.eclipse.jetty:jetty-util:9.4.12
    |   |   --- org.eclipse.jetty:jetty-io:9.4.12
    |   |       --- org.eclipse.jetty:jetty-util:9.4.12
...

(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.

If for whatever reason you need a custom project layout, add the following lines to your build.gradle file :
sourceSets {
    main {
        java {
            srcDirs = ['src99/main/java']
        }
        resources {
            srcDirs = ['src99/main/resources']
        }
    }
    test {
        java {
            srcDirs = ['src99/test/java']
        }
        resources {
            srcDirs = ['src99/test/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).

In order to change the build folder where Gradle puts the temporary and final output files, write the following in your build.gradle file:
project.buildDir = 'gradle-build'

The Gradle Build File Is a Groovy Script

Let’s revise the EchoLibrary example build.gradle file :
// The EchoLibrary build file
plugins {
    id 'java-library'
}
java {
    sourceCompatibility = JavaVersion.VERSION_1_8
    targetCompatibility = JavaVersion.VERSION_1_8
}
repositories {
    jcenter()
}
dependencies {
    testImplementation 'junit:junit:4.12'
}

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 ).

For example, if you wanted to add a runtimeOnly dependency only if some system property is defined, and furthermore wanted to output a corresponding diagnostic message, you could write the following:
...
dependencies {
  if(System.getProperty("add.math") != null) {
    println("MATH added")
    runtimeOnly group: 'org.apache.commons',
                name: 'commons-math3', version: '3.6.1'
  }
  ...
  testImplementation 'junit:junit:4.12'
}
...

You could now call any task with the extra option -Dadd.math added to see the conditional statement and console output working.

Script Variables

For increased readability and maintenance optimization, you can add variables (properties) to your build file. To do so, you can use an ext { } call:
...
ext {
    MATH_VERSION = '3.6.1'
    JUNIT_VERSION = '4.12'
}
dependencies {
  implementation group: 'org.apache.commons',
      name: 'commons-math3', version: MATH_VERSION
  testImplementation "junit:junit:${JUNIT_VERSION}"
}
...

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.

If the variable scope is limited to the current closure (inside a { }), you can also use the standard Groovy local variable declaration:
...
dependencies {
  def MATH_VERSION = '3.6.1'
  def JUNIT_VERSION = '4.12'
  implementation group: 'org.apache.commons',
      name: 'commons-math3', version: MATH_VERSION
  testImplementation "junit:junit:${JUNIT_VERSION}"
}
...

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.

To define your own task, you write the following anywhere in your build.gradle script file:
task hello {
  group = 'build'
  description = 'Hello World'
  println 'Hello world! CONFIG'
  doFirst {
    println 'Hello world! FIRST'
  }
  doLast {
    println 'Hello world! LAST'
  }
}

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.

It is possible to add instructions to the task’s action list at a later point, by writing:
hello.doLast {
  println 'Hello world! MORE LAST'
}
hello.doFirst {
  println 'Hello world! MORE FIRST'
}
You can add your custom task to the dependent’s list of existing tasks, or add existing tasks to the dependent’s list of the new task. To do so, write the following, for example:
build.dependsOn hello
hello.dependsOn build

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

If you use the wrapper task or the Eclipse Gradle plugin to start a new project, the wrapper scripts are installed, which allow you to run Gradle without any Gradle installation on the operating system (Java must be working, though). You can see that from the following files:
gradlew
gradlew.bat
gradle
  |- wrapper
        |- gradle-wrapper.jar
        |- gradle-wrapper.properties

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.

To build such a multi-project from inside Eclipse, first create a normal Gradle project as described previously. Then, open the settings.gradle file and add the following line:
include 'proj1', 'proj2'

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.

Right-click the project and choose Gradle➤Refresh Gradle Project. Eclipse will update the Project Explorer and show the main project and the two subprojects as different entries; see Figure 3-7.
../images/499016_1_En_3_Chapter/499016_1_En_3_Fig7_HTML.jpg
Figure 3-7

Gradle multi-project in Eclipse

Due to a bug in the Gradle plugin, you have to fix the JRE library assignment for all three entries. On each of them, right-click and then choose Properties➤Libraries. Remove the wrong entry, then click Add Library (to classpath)➤JRE System Library➤Workspace Default JRE (or whatever suits your needs). The error markers should now be gone, as shown in Figure 3-8.
../images/499016_1_En_3_Chapter/499016_1_En_3_Fig8_HTML.jpg
Figure 3-8

Gradle multi-project in Eclipse, fixed

Each subproject can be configured independently using its own build.gradle file, but it is also possible to refer to subprojects from the root project’s build.gradle file:
// referring to a particular sub-project
project(':proj1') { proj ->
    // adding a new task to proj1
    task('hello').doLast { task ->
       println "I'm $task.project.name" }
}
// we can directly address tasks
project(':proj1').hello {
  doLast { println "I'm $project.name" }
}
// or, referring to all sub-projects
subprojects {
    task hello {
        doLast { task ->
        println "I'm $task.project.name"
    }
  }
}
// or, referring to the root project and all sub-projects
allprojects {
    task hello {
        doLast { task ->
        println "I'm $task.project.name"
    }
  }
}
We can address the root project from inside the configuration of a subproject via the rootProject variable:
task action {
    doLast {
        println("Root project: " +
            "${rootProject.name}")
    }
}

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

A good candidate for a custom task is a deployment process. We can use the standard build task to create a WAR or EAR file, but in order to deploy it on a local development server, a custom Gradle task comes in handy. Throughout the book, we will use the following tasks for deployment and “un-deployment” on a local GlassFish server:
task localDeploy(dependsOn: build,
             description:">>> Local deploy task") {
  doLast {
    def FS = File.separator
    def glassfish = project.properties['glassfish.inst.dir']
    def user = project.properties['glassfish.user']
    def passwd = project.properties['glassfish.passwd']
    File temp = File.createTempFile("asadmin-passwd",
        ".tmp")
    temp << "AS_ADMIN_${user}=${passwd} "
    def sout = new StringBuilder()
    def serr = new StringBuilder()
    def libsDir = "${project.projectDir}${FS}build" +
        "${FS}libs"
    def procStr = """${glassfish}${FS}bin${FS}asadmin
        --user ${user} --passwordfile ${temp.absolutePath}
        deploy --force=true
        ${libsDir}/${project.name}.war"""
    // For Windows:
    if(FS == "\") procStr = "cmd /c " + procStr
    def proc = procStr.execute()
    proc.waitForProcessOutput(sout, serr)
    println "out> ${sout}"
    if(serr.toString()) System.err.println(serr)
    temp.delete()
  }
}
task localUndeploy(
             description:">>> Local undeploy task") {
  doLast {
    def FS = File.separator
    def glassfish = project.properties['glassfish.inst.dir']
    def user = project.properties['glassfish.user']
    def passwd = project.properties['glassfish.passwd']
    File temp = File.createTempFile("asadmin-passwd",
        ".tmp")
    temp << "AS_ADMIN_${user}=${passwd} "
    def sout = new StringBuilder()
    def serr = new StringBuilder()
    def procStr = """${glassfish}${FS}bin${FS}asadmin
        --user ${user} --passwordfile ${temp.absolutePath}
        undeploy ${project.name}"""
    // For Windows:
    if(FS == "\") procStr = "cmd /c " + procStr
    def proc = procStr.execute()
    proc.waitForProcessOutput(sout, serr)
    println "out> ${sout}"
    if(serr.toString()) System.err.println(serr)
    temp.delete()
  }
}
These tasks depend on a properties file. Gradle automatically tries to read a properties file named gradle.properties and, if it exists, creates a map from the properties and puts it into the project.properties variable. We create such a file in the project folder, and let it read as follows:
glassfish.inst.dir = /path/to/glassfish/inst
glassfish.user = admin
glassfish.passwd =

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.

If you didn’t use the Eclipse Gradle plugin to start a Gradle project, you can use the wrapper task to create the wrapper. In this case, Gradle must be installed on your OS. The Linux script reads as follows:
java -version
# observe output
# if you want to specify a different JDK:
export JAVA_HOME=/path/to/the/jdk
cd /here/goes/the/project
gradle init wrapper
For Windows, it reads as follows:
java -version
# observe output
# if you want to specify a different JDK: set JAVA_HOME=C:path o hejdk
chdir heregoes heproject
gradle init wrapper

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.

To check the wrapper installation, you can list the available tasks from inside the project directory via the following:
./gradlew tasks
# Windows:   gradlew tasks
The output should be something like this:
> Task :tasks
--------------------------------------------------------
All tasks runnable from root project
--------------------------------------------------------
Build Setup tasks
-----------------
init - Initializes a new Gradle build.wrapper - Generates Gradle wrapper files.
[...]
You can see the complete synopsis of the gradlew (gradlew.bat for Windows) wrapper command if you enter the following:
./gradlew -help
# Windows:   gradlew -help
A non-exhaustive list of interesting and important option parameters is shown in Table 3-3. Specify any tasks to be executed behind the option list.
Table 3-3

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.

Tasks can have options and parameters. In order to use the tasks task (show all task), for example, you can add --all as an option:
./gradlew tasks --all
# Windows:   gradlew tasks --all

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.

For our little EchoLibrary example project, navigate to the project folder and then execute the following:
./gradlew build
# Windows:   gradlew build

The output JAR called EchoLibrary.jar is generated inside the build/libs folder.

Note

For simplicity in the rest of the book, we will only show console Gradle commands, and only the Linux variant.

Installing MVC

In order to be able to use Java MVC, from a Gradle perspective, we need to check a few things. First, we configure Java MVC as a web application. For this reason, we create a web project and use the WAR plugin. Inside build.gradle, add the following:
plugins {
    id 'war'
}
Next we add the Jakarta EE 8 API, the Java MVC API, and a Java MVC implementation inside the dependencies section of build.gradle. This comes together with a repository specification, the usual JUnit test library inclusion, and the indication that we want to use Java 1.8:
plugins {
    id 'war'
}
java {
    sourceCompatibility = 1.8
    targetCompatibility = 1.8
}
repositories {
    jcenter()
}
dependencies {
   testImplementation 'junit:junit:4.12'
   implementation 'javax:javaee-api:8.0'
   implementation 'javax.mvc:javax.mvc-api:1.0.0'
   implementation 'org.eclipse.krazo:krazo-jersey:1.1.0-M1'
   // more dependencies...
}
// ... more tasks

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:

task a {
    println "Hi, I'm A"
}
task b {
    println "Hi, I'm B"
}
  • 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 default project layout for all Gradle plugins is as follows:
src
  |- main
  |     |- java
  |     |     |- <java source files>
  |     |- resources
  |           |- <resource files>
  |
  |- test
        |- java
        |     |- <java source files>
        |- resources
              |- <resource files>
build
  |- <any files built by Gradle>
build.gradle       <Gradle build file>
settings.gradle    <(Sub-)Project settings>
gradle.properties  <optional project properties>

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.

Gradle loads libraries from repositories if it determines that the project refers to such libraries. You specify repositories in a repositories { } section inside build.gradle:
repositories {
    repoSpec1   (repository specification, see below)
    repoSpec2
   ...
}
You can use the following as repository specifications:
  • 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.

Once you identify the configurations you need, you specify a list in the dependencies { } section of your build.gradle file:
dependencies {
   implementation 'org.apache.commons:commons-math3:3.6.1'
   // This is the same:
   implementation group:'org.apache.commons',
        name:'commons-math3',
        version:'3.6.1'
   // You can combine:
   implementation 'org.apache.commons:commons-math3:3.6.1',
        'org.apache.commons:commons-lang3:3.10'
   // or like that:
   implementation(
     [ group:'org.apache.commons',
       name:'commons-math3', version:'3.6.1' ],
     [ group:'org.apache.commons',
       name:'commons-lang3', version:'3.10' ]
)
   // or like that:
   implementation 'org.apache.commons:commons-math3:3.6.1'
   implementation 'org.apache.commons:commons-lang3:3.10'
   testImplementation 'junit:junit:4.12'
}

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 ).

For increased readability and maintenance optimization, you can add variables (properties) to your build file. To do so, use an ext { } call:
...
ext {
   MATH_VERSION = '3.6.1'
   JUNIT_VERSION = '4.12'
}
dependencies {
  implementation group: 'org.apache.commons',
      name: 'commons-math3', version: MATH_VERSION
  testImplementation "junit:junit:${JUNIT_VERSION}"
}
...

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.

To define your own task, you write the following anywhere in your build.gradle script file:
task hello {
  group = 'build'
  description = 'Hello World'
  println 'Hello world! CONFIG'
  doFirst {
    println 'Hello world! FIRST'
  }
  doLast {
    println 'Hello world! LAST'
  }
}

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.

You can add your custom task to the dependent’s list of existing tasks, or add existing tasks to the dependent’s list of the new task. To do so, write the following, for example:
build.dependsOn hello
hello.dependsOn build

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.

If you didn’t use the Eclipse Gradle plugin to start a Gradle project, you can use the wrapper task to create the wrapper. In this case, Gradle must be installed on your OS. The Linux script reads as follows:
java -version
# observe output
# if you want to specify a different JDK:
export JAVA_HOME=/path/to/the/jdk
cd /here/goes/the/project
gradle init wrapper
The Windows script is as follows:
java -version
# observe output
# if you want to specify a different JDK:
set JAVA_HOME=C:path o hejdk
chdir heregoes heproject
gradle init wrapper

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.

You can see the complete synopsis of the gradlew (gradlew.bat for Windows) wrapper command if you enter the following:
./gradlew -help
# Windows:   gradlew -help
Tasks can have options and parameters as well. In order to use the tasks task (show all task), for example, you can add --all as an option:
./gradlew tasks --all
# Windows:   gradlew tasks --all

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 order to be able to use Java MVC, from a Gradle perspective, we need to verify a few things. First, we configure Java MVC as a web application. For this reason, we create a web project and use the WAR plugin. Inside build.gradle, add the following:
plugins {
    id 'war'
}
Next we add the Jakarta EE 8 API, the Java MVC API, and a Java MVC implementation inside the dependencies section of build.gradle. This comes together with a repository specification, the usual JUnit test library inclusion, and the indication that we want to use Java 1.8:
plugins {
    id 'war'
}
java {
    sourceCompatibility = 1.8
    targetCompatibility = 1.8
}
repositories {
    jcenter()
}
dependencies {
   testImplementation 'junit:junit:4.12'
   implementation 'javax:javaee-api:8.0'
   implementation 'javax.mvc:javax.mvc-api:1.0.0'
   implementation 'org.eclipse.krazo:krazo-jersey:1.1.0-M1'
   // more dependencies...
}
// ... more tasks

In the next chapter, we talk about a clean "Hello World" style project using the development workflow we just described.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.142.12.240