Chapter 10. IDE support and tooling

This chapter covers

  • Using IDE plugins to generate project files
  • Managing Gradle projects in popular IDEs
  • Embedding Gradle with the tooling API

While Gradle’s target runtime environment is the command line, editing build scripts happens in a text editor. The types of editors that developers use range from simple screen-oriented editors like vi or Emacs, to full-blown integrated development environments (IDEs) like Eclipse and IntelliJ IDEA. IDEs can boost a developer’s productivity tremendously. Functionality like syntax highlighting, navigation through keyboard shortcuts, refactoring, and code completion generation save valuable time during development and make implementing code a more enjoyable experience. Developing Gradle code should be no different.

IDEs store the configuration data for projects in project files. The format of these files, usually described in XML, is different from vendor to vendor. Historically, popular IDEs didn’t incorporate integration support for Gradle, so Gradle had to provide plugins to generate these files. In this chapter, we’ll look at the plugins provided by Gradle to generate project metadata for popular Java IDEs. These plugins are effective tools in deriving most of this metadata from your build script definition. While the generated project files are usually a good start, you often need more fine-grained control to customize the metadata. We’ll discuss how to use the DSL exposed by these plugins to adjust this metadata to your individual needs.

With the increasing popularity of Gradle, IDE vendors have provided first-class, built-in support for managing Gradle projects. We’ll explore how to import existing projects backed by Gradle build scripts, navigate these projects, and execute Gradle tasks directly in the IDE. The breadth of this functionality is dependent on the IDE product. In this chapter, we’ll compare the feature sets provided by Eclipse, IntelliJ IDEA, NetBeans, and Sublime Text.

Most IDE vendors use the tooling API to embed Gradle into their products. The tooling API is part of Gradle’s public API and is used to execute and monitor a build. While the API’s main focus is to embed Gradle into third-party applications, it can also be used in other situations. You’ll get to know one of these use cases and apply the API in practice. You’ll start by using Gradle’s IDE plugins to generate project files for your To Do application.

10.1. Using IDE plugins to generate project files

IDEs describe organizational units with the notation of a project, similarly to a Gradle project. A project defines a type (for example, web versus desktop application), external dependencies (for example, JAR, source, and Javadoc files), plus individual settings. With the help of project files, a project can be opened in an IDE and can allow for sharing configuration data with other developers. Unfortunately, the formats of these project files are not unified across IDE products. Among the most common formats are XML and JSON.

Gradle allows for generating IDE project files with the help of plugins. The standard Gradle distribution provides two out-of-the-box plugins: Eclipse and IDEA. Each plugin understands how to model IDE-specific project files. The plugins also expose a powerful DSL for customizing the generated project settings. To generate project files, you’ll need to apply the IDE plugin to your build script, execute the task provided by the plugin, and import the generated project files into your IDE, as shown in figure 10.1.

Figure 10.1. IDE project generation with Gradle

To be able to share project files, you’d usually check them into your VCS alongside your source code. When another developer checks out the project from the VCS, they can directly open the project in the IDE and start working. Using the Gradle IDE plug-ins makes this step redundant because you describe the project settings using the plugin’s DSL. The project files can be regenerated at any time, similarly to the process of compiling source code to class files.

In this chapter, you’ll model project files to enable your To Do application to be loaded in the IDEs Eclipse, IntelliJ IDEA, and Sublime Text. Therefore, Gradle’s IDE plugins need to be able to translate the individual needs of your build into the IDE’s configuration data. In this book, you added very specific configuration elements that stand out from a simple Gradle project:

  • Multiproject build definition including compile-time project dependencies
  • Custom configurations used to declare external dependencies
  • Custom source sets for integration and functional tests

You’ll learn how to describe these rules with the help of the DSL exposed by the Gradle plugins. You’ll start by generating Eclipse project files.

10.1.1. Using the Eclipse plugins

Eclipse (http://www.eclipse.org/) is probably the most popular and widely used IDE for Java projects. It’s completely open source and can be extended by plugins to add specialized functionality, such as support for Groovy projects and the use of version control systems like Git. You need a good understanding of the format of Eclipse project files before you start generating them because the plugin’s DSL elements target specific files.

Project format and files

Eclipse stores configuration data per project. This means that every project participating in a multiproject build contains its own set of Eclipse project files and directories. All configuration data is described in XML. There are three types of files/directories:

  • .project: The name of this file is self-explanatory—it stores the basic information about a project. It contains the name, description, references of other projects or resources, and the type of project.
  • .classpath: This file describes the classpath entries to referenced external libraries and other projects.
  • .settings: This directory is optional for a project. It contains workspace-specific settings. The file within the directory stores settings like the Java compiler version and source code version compliance.

In the setting of your To Do application, the generated project files will look similar to figure 10.2.

Figure 10.2. Eclipse project files

Each project in the hierarchy, root project, and subprojects has its own set of project files. Next, you’ll apply the relevant Gradle plugins to your project and generate the project files.

Applying and executing the plugins

The Gradle distribution comes with two Eclipse plugins: eclipse and eclipse-wtp. The eclipse plugin is responsible for generating standard Eclipse configuration data. The plugin named eclipse-wtp builds on top of the eclipse plugin and generates configuration files to be used with Eclipse’s Web Tools Platform (WTP). WTP provides tools for developing Java EE applications and can be installed as an optional Eclipse plugin. The WTP plugin simplifies the creation of typical web artifacts like web descriptors, Servlets, and JSP files. It also provides support for deploying WAR files to various web containers, which can come in handy if you need to debug your running application from your IDE.

At its core, your To Do application is a web application, which makes it a good candidate to apply both Gradle Eclipse plugins. First, apply the eclipse plugin to all Gradle projects of your application:

allprojects {
   apply plugin: 'eclipse'
}

Applying the plugin to the allprojects configuration block will create project files for the root project and all subprojects. The only project that you need to generate WTP configuration files for is the web project. You can apply the plugin as shown in the following code snippet:

project(':web') {
   apply plugin: 'eclipse-wtp'
}

With these two plugins in place, you’re ready to generate Eclipse project files by executing their provided tasks. Two tasks are of high importance: eclipse and cleanEclipse. The task eclipse generates all Eclipse project files, including .project, .classpath, and the settings files under the directory .settings. The task cleanEclipse removes all existing Eclipse project files. Try executing the task eclipse on the root level of your multiproject hierarchy:

The task eclipse automatically executes many dependent tasks. Each of these dependent tasks is responsible for generating a specific type of project file. For example, the task eclipseClasspath generates the content of the file .classpath. The following directory tree shows the end result:

.
├── .project
├── model
│   ├── .classpath
│   ├── .project
│   └── .settings
│       └── org.eclipse.jdt.core.prefs
├── repository
│   ├── .classpath
│   ├── .project
│   └── .settings
│       └── org.eclipse.jdt.core.prefs
└── web
    ├── .classpath
    ├── .project
    └── .settings
        ├── org.eclipse.jdt.core.prefs
        ├── org.eclipse.wst.common.component
        └── org.eclipse.wst.common.project.facet.core.xml

We already discussed the purpose of the configuration files .project and .classpath. Let’s take a closer look at one of the generated settings files. A prominent settings file available to all subprojects is org.eclipse.jdt.core.prefs. This file stores configuration data specific to Java projects provided by Eclipse’s Java development tools (JDT). One example of a JDT setting is the Java compiler version.

If you open the generated project files in Eclipse right now, what would you have achieved with the default Gradle plugin configuration? All of the projects would be recognized as Java or Groovy projects (in Eclipse this is described as project nature), the correct source paths would be set, and dependencies for default configurations defined by the Gradle Java plugin would be linked. The prep work for using Eclipse WTP tooling would be done. This is a lot of configuration that the Gradle plugins provide out of the box without any additional customization from your side. So what’s missing? Any custom configurations aren’t recognized automatically. In this case, these are functTestCompile and functTestRuntime, two configurations you defined for declaring functional test dependencies. You’ll fix this by customizing the generation of the project files.

Customizing the configuration

The Gradle Eclipse plugins expose an extensive DSL for customizing almost every aspect of the project file generation process. Table 10.1 shows the important key properties that provide access to the Eclipse generation model.

Table 10.1. Eclipse plugin configuration properties

Property Name

Gradle API Class

Plugin

Description

project EclipseProject eclipse Configures project information
classpath EclipseClasspath eclipse Configures classpath information
jdt EclipseJdt eclipse Configures JDT information
wtp.component EclipseWtpComponent eclipse-wtp Configures WTP component information
wtp.facet EclipseWtpFacet eclipse-wtp Configures WTP facet information

Each concern is nicely separated and can be configured individually by using the dedicated property. In the following section, you’ll see each of these properties in action. Project setups are different and can be very specific. It’s likely that you won’t find your use case covered by the example. If you feel that you need to dig deeper, the best place to start is the Gradle DSL guide. Also keep in mind that it’s a good idea to delete existing project files whenever you change the configuration and want to regenerate the project files. You can easily achieve this by executing the task cleanEclipse:

$ gradle cleanEclipse eclipse

The Gradle Eclipse plugin derives many configuration values for Eclipse project files from the implicit or explicit build script configuration. For example, the Eclipse project name is taken from the Gradle property project.name. All of the preconfigured values can be reconfigured.

You’ll start by fine-tuning the project details of your root project. You can easily override the default value of the Eclipse project by assigning a new value to the property eclipse.project.name, as shown in the following listing. You’ll also set various other properties.

Listing 10.1. Setting root project properties

If you just want to assign properties to the subprojects of your application, you can put the specific configuration into the subprojects configuration block. The next listing shows how to set values for JDT properties and how to influence the classpath generation.

Listing 10.2. Setting JDT and classpath properties for all subprojects

Eclipse configuration to individual subprojects is applied on top of already existing configuration data. All you need to do is add another eclipse configuration block in the build script of the subproject. This method can also be used if you want to redefine an already set configuration value. The following listing demonstrates how to set the project description, add the custom Gradle configurations, and individualize WTP configuration data.

Listing 10.3. Fine-tuning the Eclipse properties of the web subproject

These examples give you an idea of how easy it is to customize the generated configuration by the properties exposed through the Gradle plugin DSL. The exposed properties cover many of the commonly used configuration options. However, it’s impossible for the DSL to reflect configuration options for third-party Eclipse plugins or personalized user customizations. For that purpose, the DSL provides hooks into the model generation that allow you to manipulate the resulting XML project files.

Manipulating the generated configuration

There are two ways to customize the generated project files. One is to directly reach into the XML domain object model (DOM) using the withXml hook. The other is to register the merge hook beforeMerged or whenMerged, which allows for working directly with the domain object representing the Eclipse metadata model. Let’s see the usage of these hooks by implementing a practical example.

When applying the Gradle eclipse-wtp plugin to your web project, you can generate project files for basic functionality in Eclipse WTP. Unfortunately, the basic plugin settings don’t preconfigure support for editing JavaScript files (including syntax highlighting and code completion).

In Eclipse, a unit of functionality is called a facet. One example of a facet is the JavaScript editing functionality. To configure the JavaScript facet, you’ll need to specify the value wst.jsdt.web as the facet key. The next listing shows how to append a node to the XML DOM representation that adds the JavaScript facet with version 1.0.

Listing 10.4. Adding the WTP JavaScript facet using the XML hook

After adding this configuration and regenerating the project files, you’ll see that the file web/.settings/org.eclipse.wst.common.project.facet.core.xml contains an entry for your JavaScript facet.

The same configuration can be achieved using the merge hooks. You’ll use the hook whenMerged. When applying the hook in the context of the WTP facet element, the closure is provided with an instance of WtpComponent. In the next listing, you’ll instantiate a new instance of type Facet, provide the data you need in the constructor, and add it to the list of facets.

Listing 10.5. Adding the WTP JavaScript facet using a merge hook

Choosing the “right” type of hook

You may ask yourself, which of these hooks should be used in what situation, or is there even a best practice? In short, there isn’t. Gradle provides a variety of flexible options. The option you choose for your project is often subjective.

My personal preference is to go with merge hooks because I can directly work with domain objects that represent my configuration data. These domain objects usually describe the data they need to work correctly. If you’re unsure about what data needs to be provided, you can easily answer this question by looking at the Javadocs of the Eclipse plugin.

If you need to add a configuration that isn’t backed by domain objects available in the Gradle API, you can always fall back to the XML hook. The XML hook doesn’t run any validation on the data you provide, which makes it easy to provide unconventional configuration data. To find out the structure of available Eclipse XML configuration elements, please refer to the Eclipse documentation.

It’s time to see the results of your hard work. Next, you’ll import the generated project files in Eclipse.

Importing the projects

The Eclipse distribution comes in various packages targeted for the type of projects you’re working on. Because you’re working on a Java Enterprise project, the package best suited is Eclipse IDE for Java EE Developers. The package contains many useful plugins you’ll want to use. If you haven’t already done so, download the package from the Eclipse homepage and install it on your machine.

The standard Eclipse distribution doesn’t provide an easy way of importing hierarchical projects. Instead, you’ll need to import each project individually. To import a single project, choose the menu item File > Import... > General > Existing Projects into Workspace. Press the Next button and browse to the root directory of the project you want to import. If Eclipse can find a valid project file, it’ll display it in the list of projects ready to be imported. After pressing the Finish button, you’ll find the project in the Package Explorer tab. If you repeat this process for the root project and all subprojects, your Eclipse workspace should look similar to figure 10.3.

Figure 10.3. Imported projects in Eclipse

Congratulations—if you’re an Eclipse user, you successfully set up your project for yourself and your peers in a reproducible manner. At any time, you can regenerate the project files. Later, we’ll also touch on a more sophisticated Eclipse distribution called the SpringSource Tool Suite (STS) that provides out-of-the-box support for importing hierarchical Gradle projects. In the next section, you’ll learn how to achieve the same for users of IntelliJ IDEA.

10.1.2. Using the IDEA plugin

IntelliJ IDEA (http://www.jetbrains.com/idea/) is a commercial IDE for working with JVM-based projects. It provides extensive support for popular frameworks and is backed by a suite of integrated developer tools. While many of its features are preinstalled with the core product, it can be extended by plugins. Let’s start with a quick tour of IntelliJ’s project files.

Project format and files

IntelliJ stores project files in the root directory of a project. The actual data is formatted in XML. We differentiate between project files with the following file extensions:

  • .ipr: The file with this extension stores the core project information. In a multi-project setting, referenced subprojects are stored here.
  • .iml: In IntelliJ, a unit of functionality (a.k.a. a module) is stored in an .iml module file. A module file holds configuration data about source code, build scripts, and relevant descriptors. Each Gradle project in a multiproject build maps to one module file.
  • .iws: The .iws file contains workspace-specific settings. There’s only one settings file per single project or multiproject setting.

Your To Do application would be based on the project files shown in figure 10.4.

Figure 10.4. IntelliJ IDEA project files

Every project—root and subproject—contains at least the module file. The file with the extension .ipr and the workspace settings file are stored on the level of the root project. Next, you’ll apply and execute the Gradle IDEA plugin to generate these files.

Applying and executing the plugin

The Gradle standard distribution ships with the core plugin idea. You can use this plugin to generate all required IntelliJ project files previously discussed. To generate the project files for all projects of your To Do application, apply it in the allprojects configuration block of the root build script:

allprojects {
   apply plugin: 'idea'
}

The main task provided by the plugin is called idea. On execution, it generates all project files shown in figure 10.4. The command-line output of the task looks like the following:

You can already open the full IntelliJ project with the generated project files. For now, hold off on that, because the IDEA plugin doesn’t recognize custom source sets and configuration. This can only be achieved by customizing the configuration. Next, you’ll learn how to fine-tune the generated configuration data.

Customizing the configuration

The IDEA Gradle plugin exposes a rich DSL for setting properties to tweak the generation of project, module, and workspace files. Table 10.2 shows the relevant DSL configuration blocks that give you access to the internal model.

Table 10.2. IDEA plugin configuration properties

Property Name

Gradle API Class

Plugin

Description

project IdeaProject idea Configures project information
module IdeaModule idea Configures module information
workspace IdeaWorkspace idea Configures workspace information

We’ll explore each of the configuration elements in the context of your To Do application. If at any time you want to set a property that isn’t mentioned in the examples, make sure to have the Gradle DSL guide handy. After changing the configuration, it’s a good idea to fully replace the existing project files with the cleanIdea command:

$ gradle cleanIdea idea

The usage of the main IDE tasks is uniform among the Eclipse and IDEA plugins. This makes it easy for a user to switch between IDEs or provide support for both. You’ll start by customizing the project file. The following listing demonstrates how to set project properties on the root level of a multiproject build.

Listing 10.6. Setting root project properties

If you want to customize the configuration for all subprojects participating in a multiproject build, use the subprojects configuration block. Next, you’ll provide instructions to download the source files for all external dependencies in your Java projects. The following listing shows how to make the sufficient configuration for all module files.

Listing 10.7. Setting module properties for all subprojects

As mentioned earlier, the IDEA plugin doesn’t recognize custom source sets right off the bat. You can easily change that by modifying the build scripts for the repository and web subprojects. Start with the source set integrationTest defined by the subproject repository. Thankfully, you don’t have to repeat the directory path again. Gradle allows for accessing the path directly via its API. The following listing demonstrates a perfect example of how Gradle’s Java plugin DSL can be used to retrieve the required information to apply the IDEA module DSL.

Listing 10.8. Adding the custom source set for the repository subproject

You’ll want to apply the same type of customization to the web module. Listing 10.9 shows how to add the test source set functionalTest. In addition to this customization, the listing also demonstrates how to add dependencies defined by your custom configurations to the IDE’s test compilation scope.

Listing 10.9. Adding custom source set and configurations for the web subproject

After creating this configuration setup, you can regenerate the IntelliJ project files and open the project without any problems in the IDE. Before you do, let’s also look at the XML and merge hooks provided by the plugin.

Manipulating the generated configuration

The IDEA plugin provides the same kind of low-level customization hooks as the Eclipse plugin. In fact, they even follow the identical naming convention. XML modifications can be achieved with the withXml hook to merge modifications with the methods beforeMerge and afterMerge.

While the IDEA plugin does a good job of deriving a default configuration from the build script, it certainly doesn’t pick up every desirable setting you need to get started right away as an end user. Let’s discuss an example. Gradle comes with the JetGradle plugin preinstalled to support executing Gradle build scripts. To be able to use any functionality of the plugin, a Gradle build script has to be selected first. The IDEA plugin doesn’t make this selection for you when generating the project metadata. Thankfully, you can use the XML and merge hooks to generate this configuration.

Let’s see how to use the XML hook for this purpose. In the next listing, you first gain access to the XML root node, then append a new component XML tag as its child node, and finally assign the required configuration to point to your root project’s build script.

Listing 10.10. Preconfiguring project settings with the XML hook

Unfortunately, you can’t achieve the same customization with a merge hook. In comparison to the domain model exposed by the Eclipse plugin, the API of the IDEA plugin comes with fewer domain model representations. Your best bet is to implement the desired functionality with the XML hook, which provides you with maximum flexibility.

To give you an idea of the usefulness of the merge hooks, let’s look at an example. Instead of using the properties exposed by idea.project, you can also use the plugin’s project domain models. The following listing demonstrates how to set the JDK name and language level of your IntelliJ project using the whenMerged hook.

Listing 10.11. Preconfiguring project settings using a merge hook

Importing the projects

To take full advantage of all features provided by IntelliJ, download the Ultimate Edition. If you don’t buy a license key for it, you can still test it for 30 days. After installing IntelliJ on the local machine, you’re ready to import the project hierarchy. In IntelliJ, you can directly import the full multiproject hierarchy by pointing it to the root-level project file. In the menu bar, choose File > Open... and pick the generated .ipr file from the directory browser. You should end up with a project setup similar to figure 10.5.

Figure 10.5. Imported projects in IntelliJ IDEA

Eclipse and IntelliJ IDEA are among the major players when it comes to feature-rich IDEs for JVM language development. If you’re a NetBeans user, you’re out of luck. At the time of writing, there’s no published plugin that allows for generating project files with a customizable DSL approach.

IDEs provide the best support for frameworks and tooling. However, some developers prefer a more minimalistic editing environment: plaintext editors or power editors. They’re lightweight and can be extremely effective with the right key bindings. In recent times, the power editor Sublime Text has become extremely popular. In the next section, we’ll discuss how to generate project files for this editor by using a third-party plugin.

10.1.3. Using the Sublime Text plugin

Sublime Text (http://www.sublimetext.com/) is a sophisticated text editor with support for a wide range of programming languages including Java, Groovy, and Scala. The basic functionality of the tool can be extended by custom plugins. Sublime Text can be downloaded and evaluated for free. Continued use requires you to buy a license.

Project format and files

Sublime’s set of project files is simple and easy to understand. It differentiates between two types of files, each of which stores configuration data as JSON:

  • .sublime-project: The file with this extension contains the project definition consisting of source paths, the classpath, and build tool commands.
  • .sublime-workspace: The workspace file stores user-specific data, such as currently open files and modified settings.

In the context of your To Do application, a typical project setup would consists of one .sublime-project file per Gradle project. After working with the project in the editor, Sublime Text will automatically create the workspace file. A workspace file can exist for any of the projects, not just the root project. Figure 10.6 illustrates the project files in the directory tree.

Figure 10.6. Sublime Text project files

Similar to the Eclipse and IDEA Gradle plugins bundled with the Gradle distribution, you can generate Sublime Text project files with the help of a third-party plugin. Next, you’ll explore its functionality by using it for your application.

Applying and executing the plugin

At the time of writing, the Sublime Text Gradle plugin (https://github.com/phildopus/gradle-sublimetext-plugin) is at an early stage of development and only provides limited functionality. Its core feature is generating and customizing project files. As an add-on, it allows for preparing the project to execute Gradle tasks for Java projects from within the IDE.

The following listing shows the content of your root project build script that declares the plugin and adds it to the classpath. Because you want to generate Sublime Text project files for all projects of your application, apply the plugin within the allprojects configuration block.

Listing 10.12. Applying the Sublime Text plugin to all projects of your build

It’s time to generate the project files. If you execute the task sublimeText from your root project, you should end up with the following command-line output:

With the default settings of the plugin, the generated project files contain mere pointers to the directory path. You can open the project and edit the files, but you won’t be able to compile the code with Gradle. Next, you’ll customize the configuration a bit more.

Customizing the configuration

Customization options are limited. Listing 10.13 shows how to exclude unwanted directories and set up the project’s source directories and classpath. By default, the plugin doesn’t make the selection for you, even though these directories aren’t necessarily relevant for working with your project within Sublime Text.

Listing 10.13. Tweaking the configuration of Sublime Text project files

The Gradle plugin doesn’t define a clean task to delete existing project files. To regenerate the changed metadata, run the task sublimeText again. The task will override existing project files. You’re ready to open the project in Sublime Text.

Importing the projects

Sublime Text is easy to download and install. Because you’re working with a multi-project build, you’ll want to see the full project hierarchy in the user interface. To import the project, choose Project > Open Project... and pick the root project’s .sublime-project file. The rendered To Do application project hierarchy should look similar to figure 10.7. Choosing Tools > Build System > Gradle triggers a Gradle build. At the time of writing, only an installed Gradle runtime can be used; your provided Gradle Wrapper is omitted.

Figure 10.7. Imported projects in Sublime Text

This concludes our discussion of generating project files for prominent IDEs and text editors. In the next section, you’ll take the inverse approach by letting the IDE analyze your build scripts to generate the project files.

10.2. Managing Gradle projects in popular IDEs

A couple of years ago, Gradle was the newcomer among the top dogs Ant and Maven. None of the IDE vendors provided any significant Gradle support. To import a project built by Gradle, you had to generate the project files using the provided Eclipse and IDEA plugins. If you used a different IDE (for example, NetBeans), you had no tooling support.

With Gradle’s increasing popularity, this has changed. Tooling vendors realized the need for first-class Gradle support. Figure 10.8 shows how the IDE acts as the middleman between the build script and Gradle runtime.

Figure 10.8. Built-in Gradle support in IDEs

You may ask yourself which method of generating project files should be preferred: generating project files via the build, or letting the IDE analyze your build code. My personal preference is to let the IDE do the heavy lifting. It’ll usually give you a good start. If you need fine-grained control over your configuration, you can bring in the Gradle IDE plugin support. You may have to be careful, though, not to directly override the existing configuration produced by the IDE. In practice, it sometimes takes a bit of playing around to get the desired result.

The following features are particularly important to IDE end users:

  • Opening a project by analyzing the existing Gradle build script and automatically setting up the correct source directories and classpath
  • Generating project files from an existing Gradle build script
  • Synchronizing project settings whenever there’s a change to the build script (for example, adding a new external dependency)
  • Executing Gradle tasks from the IDE’s user interface
  • Code completion and syntax highlighting for Gradle DSL configuration elements

In this section, we’ll compare Gradle support for three products: SpringSource STS, IntelliJ IDEA, and NetBeans. As you’ll learn, the feature sets and their effectiveness differ slightly. Let’s start by taking a closer look at SpringSource’s Tool Suite.

10.2.1. Gradle support in SpringSource STS

Earlier in this chapter, you learned how to generate project files for Eclipse. With the help of the generated project metadata, you were able to import the project into the IDE. So far, we haven’t discussed how to work with a Gradle project after importing it. The standard distribution of Eclipse doesn’t come with any Gradle integration. You’ll need to manually install the Groovy and Gradle plugins. For more information, see the relevant Eclipse marketplace pages (such as http://marketplace.eclipse.org/content/gradle-integration-eclipse) for the Gradle integration.

But why install these plugins manually, when you can do it the easy and convenient way using the Spring Tool Suite (STS) (http://www.springsource.org/sts)? STS is an Eclipse-based development environment mainly targeted for building applications using the Spring framework. The IDE also provides excellent support for importing and managing applications powered by Gradle. In this section, you’ll use its built-in Gradle support.

Installing STS with Gradle support

Installing STS is as simple as downloading the distribution from the homepage and running the installer. Alternatively, you can modify your existing Eclipse instance by stacking STS’s features on top of it. You’ll find the required installation instructions on SpringSource’s web page. The following description is based on STS version 3.2.0.

A central dashboard is integrated in STS. The dashboard contains sections for creating new projects, accessing tutorials and documentation, and installing extensions. The core idea of an extension is to give you a preconfigured Eclipse plugin for a particular language, framework, or tool. We’re mainly interested in installing extensions for Groovy and Gradle.

If you open the IDE for the first time, the dashboard is rendered in the main panel. At any time, you can also render the dashboard panel from the menu with Help > Dashboard. Click on the Extensions panel, scroll to the section Language and Framework Tooling, and tick the checkboxes next to the extensions named Gradle Support and Groovy-Eclipse, as shown in figure 10.9. You can initiate the installation process by pressing the Install button on the bottom of the dashboard panel. After successfully installing both extensions, the STS must be restarted. After the IDE restarts, you can now use full Gradle support, like importing multiproject builds, managing dependencies, DSL code completion, and integrated task execution. Let’s see these features in action.

Figure 10.9. Installing the Groovy and Gradle plugins from the dashboard

Importing a Gradle project

STS provides a wizard for importing Gradle projects. The wizard doesn’t require an application to contain existing project files. During the import process, STS analyzes the Gradle build script, derives the configuration data from the internal model, and generates the project files for you. You can bring up the wizard by choosing the menu item Import... under File, as shown in figure 10.10. In the filter text input field, type “gradle” to indicate that you want to import a Gradle project.

Figure 10.10. Gradle project import wizard

Pressing the Next button will present you with the dialog shown in figure 10.11. In this dialog, you can select the root directory of your To Do project and build the STS project hierarchy from it by pressing the Build Model button.

Figure 10.11. Importing a multiproject Gradle build

STS will correctly identify the root project and all subprojects of your application. Select all Gradle projects, as well as the relevant import options for enabling dependency management, enabling DSL support, and running Gradle Eclipse plugin tasks. Press the Finish button, and the projects are imported and will show up in the workspace as a flat folder hierarchy. As a result, the Eclipse project files are created.

Using Gradle support

You’re now ready to conveniently work on your application without ever having to leave the STS again—of course, this is only for the IDE-purists among us. Figure 10.12 shows some of the features you have at hand. On the left side, you can see the Package Explorer. It holds all of your projects. If you open one of them, you can examine the source directories and external dependencies.

Figure 10.12. Imported Gradle project in use in STS

In the editor pane, you can modify your build script. As you can see in the screenshot, you’re making good use of the DSL code completion feature (type in the first letters of a keyword and press CTRL + space).

Gradle tasks can be executed from the Gradle view. To add the view to your IDE, select the menu item Window > Show View > Other.... This will bring up the dialog Show View. Press the OK button and choose the task to be executed from the list of tasks for a project. Any command-line output is displayed in the Console tab.

Perfect! If you’re an Eclipse user, you’re all set. Next, you’ll make your IntelliJ users happy as well.

10.2.2. Gradle support in IntelliJ IDEA

Starting with version 12.1, IntelliJ has a feature set for Gradle that’s comparable to STS’s feature set. With the help of the preinstalled Gradle plugin, you can import a project by pointing to a Gradle build script, generate the IDE metadata, execute Gradle tasks directly from the IDE, and make use of code completion in the editor. Let’s look at IntelliJ’s Gradle support by showing how to import your To Do application.

Importing a Gradle project

IntelliJ understands how to render and manage hierarchical, multiproject applications. This is a big advantage over Eclipse, because the physical structure of your project is directly reflected in the IDE. All you need to do to import a multiproject application is open IntelliJ, choose the menu item File > Import Project..., and pick the root project’s Gradle build script, as shown in figure 10.13.

Figure 10.13. Selecting the Gradle build script to import

Pressing the OK button will bring you to the next dialog, shown in figure 10.14. In the dialog, you can choose the Gradle runtime and some other configuration parameters, like its home directory. If the project comes with a Gradle wrapper, IntelliJ automatically recognizes it. Not only should you use the wrapper on the command line, you also want to use it in the IDE to ensure a consistent runtime environment. Move on to the next wizard dialog by pressing the Next button.

Figure 10.14. Gradle runtime configuration

The dialog shown in figure 10.15 is all about the details for generating the project files. On the left side, you can see the project structure that IntelliJ will generate for you. On the right side of the dialog, you can change important settings of your project. The initial values presented here are derived from the configuration of your build script. If you decide to change the location of your project files or change the JDK, you can do it here. Stick to the default settings and let IntelliJ generate the project files by pressing the Finish button.

Figure 10.15. Setting project details

You may be surprised by the format of the generated project files. A closer look at the project structure reveals that IntelliJ created a new directory named .idea to store IDE metadata. This is a different format for project files than the one we saw in section 10.1.1. Newer versions of IntelliJ favor the use of this directory-based format (.idea) over the file-based approach (.ipr, .iml, .iws). After importing the application, you can start working on the code.

Using Gradle support

Figure 10.16 shows your imported Gradle project in action. In the project pane on the left, you can find the application hierarchy. To indicate modules, IntelliJ marks every Gradle subproject with a particular icon (folder with a blue square). Files with the extension .gradle are recognized as Gradle build scripts, as indicated by the Gradle icon. In the screenshot, you can see the code completion feature for Gradle’s DSL. If IntelliJ can identify a DSL keyword while typing text, the context menu will pop up and propose available configuration elements. Alternatively, you can activate the code completion feature with the keyboard shortcut CTRL + space.

Figure 10.16. Imported Gradle project in use in IntelliJ

IntelliJ calls its Gradle plugin JetGradle. You can open the JetGradle functionality from the tab panel on the right side of the editor. One of its features is the ability to analyze the project structure, display its dependencies, download them, and execute available tasks directly from the IDE. At the time of writing, the plugin isn’t smart enough to automatically import newly defined dependencies whenever a change is made to the build script. You’ll need to manually trigger a refresh. Next, we’ll look at NetBeans’s Gradle support.

10.2.3. Gradle support in NetBeans IDE

NetBeans IDE (https://netbeans.org/) is one of the top three players among the popular Java IDEs. It supports implementing Java and Groovy applications out of the box, along with the typical functionality you can expect of a first-class IDE, like refactoring capabilities, code completion, and integration with popular frameworks and tools. The IDE’s functionality can be extended by plugins.

Installing Netbeans with Gradle support

Installing the NetBeans IDE is straightforward. Download the distribution for your OS (at the time of writing, this is version 7.3) and run the installer. After a couple of minutes, the IDE is set up and you’re ready to take care of adding Gradle support.

To install Gradle support, you’ll need to download a third-party plugin from http://plugins.netbeans.org/plugin/44510/gradle-support. You can place the plugin file anywhere in your file system. In NetBeans IDE, choose the menu item Tools > Plugins. This brings up a new dialog for managing plugins. On the tab Downloaded, press the button Add Plugins.... Select your downloaded Gradle plugin file, as shown in figure 10.17.

Figure 10.17. Adding the downloaded Gradle plugin

After pressing the Open button, you’re presented with details about the plugin. In figure 10.18, you can see the version you’re about to install, the source of the plugin, and a description of its functionality. Make sure the checkbox next to the plugin name is checked and press the Install button to initiate the installation process. After a successful install, NetBeans IDE needs to be restarted.

Figure 10.18. Installing the Gradle plugin

Importing a Gradle project

Next you’ll import your To Do application into NetBeans IDE. With the help of the menu item File > Open Project you can open a new dialog that allows you to select a Gradle project. The displayed file browser conveniently displays the Gradle icon for every folder containing a Gradle build script. Navigate to the To Do project and select the root folder, as shown in figure 10.19.

Figure 10.19. Importing the Gradle project

After pressing the button Open Project, the project is imported. You’re ready to work with it in the IDE.

Using Gradle support

The project is initially opened in a tab on the left side marked Projects view. All you’ll see is the root project. Subprojects are aligned under the tree node. For convenience, expand the Subprojects node and click each of the subproject names. This will automatically add the subprojects to the top level of the Projects view, as shown in figure 10.20.

Figure 10.20. Imported Gradle project in use in NetBeans IDE

Gradle tasks can be executed by clicking a project node, bringing up the context menu, and choosing a task from the list. Every project node groups source and test packages, dependencies, and build scripts. This is great if you prefer a logical grouping of important Gradle elements. If you need to change individual files, you can switch to the Files tab at any time. In the screenshot, you can also see an opened Gradle build script in the editor. Unfortunately, the Gradle plugin doesn’t come with any support for DSL code completion.

This concludes our discussion of Gradle support within IDEs. Next up, we’ll look at Gradle’s tooling API, the API that makes it possible for all of these IDEs to provide a smooth Gradle integration.

10.3. Embedding Gradle with the tooling API

The main purpose of the tooling API is to embed Gradle into an application. Without knowing it, you already used the tooling API, because it’s the main driver for Gradle support in IDEs. The tooling API is good for achieving three main goals:

  • Executing the build with a specific version of Gradle (either via the wrapper or an installed Gradle runtime).
  • Querying the build for runtime information and its internal model (for example, tasks, dependencies, and the command-line output).
  • Listening to build events to react to them. One example is automatically downloading external dependencies in an IDE whenever the declaration is changed.

Many developers aren’t working for tool vendors—we usually work on Enterprise or open source applications that use Gradle as the build system. Why would we care about the tooling API? The tooling API is very versatile and can be applied to other use cases. Let’s explore one of them to see the API in action. In the following section, you’ll use the tooling API to implement integration testing by actively executing a build script. To verify its correct behavior, you can query for the runtime information available through the tooling API. When you integration-test a build script with the tooling API, you don’t have to use the ProjectBuilder class to emulate the creation of a project. The build script is tested from the end-user perspective and behaves as if you ran the gradle command from the console. Let’s look at an example.

In chapter 8, you developed various Gradle tasks to interact with the CloudBees backend. The following listing shows the task that retrieves information about a deployed application on RUN@cloud and prints the details on the command line.

Listing 10.14. CloudBees task for retrieving application information

There’s no easy way to fully test this task under real-world conditions because it uses properties provided on the command line and in the file gradle.properties. Let’s see how the tooling API can help you to verify its correct behavior by using the build script.

First, set up the directory structure. Put the CloudBees task into a regular Gradle build script in a directory named script-under-test. Your testing code will live in a directory named tooling-api-integ-test on the same nesting level. It holds a Gradle build script that sets up Spock as its testing framework and pulls in the tooling API dependencies. The test class implementation is called CloudBeesSpec.groovy. The final setup looks as follows:

Let’s take a quick peek at the integration test build script shown in listing 10.15. Because you’re using Spock to write your tests, you’ll need to apply the Groovy plugin. All dependencies use the testCompile configuration because you’re only planning to write tests.

Listing 10.15. Preparing the integration tests

Listing 10.16 shows the content of the test class CloudBeesSpec.groovy. It defines a single test method that uses the Gradle tooling API to execute the CloudBees task named cloudBeesAppInfo. Not only do you want to execute the task, you also want to make sure it behaves as expected. The task only produces command-line output, so you’ll need to parse the standard output stream to see if the correct application information is printed. This functionality is testable in a unit test because a Gradle task doesn’t allow for setting a mock object for the logger instance.

Listing 10.16. Integration testing using the tooling API

The intention of the test method should be clear. Let’s also analyze how you use the Gradle tooling API within the test class CloudBeesSpec. As shown in the listing, you defined a method named withGradleConnector that does the heavy lifting. The tooling API is used in five steps:

  1. Create an instance of the class GradleConnector—the main entry point to invoking a build script.
  2. Configure the GradleConnector instance by setting the expected Gradle version, installation location, and the project directory containing the build script to invoke. By default, the wrapper is automatically downloaded and used.
  3. Connect to the target build script by invoking the connect() method.
  4. Provide build parameters, such as the tasks, command-line arguments, and the output stream you want to write to.
  5. After the build script task is executed, the connection should be closed to free up the resource by calling the method close().

This is the tooling API in a nutshell. There are many more options to explore, but this example should give you an idea of how powerful the tooling API is. You can find more information on usage patterns and configuration options in the user guide at http://www.gradle.org/docs/current/userguide/embedding.html.

10.4. Summary

Gradle’s main runtime environment is the command line. While this feature makes the build portable, many developers are most productive in a visual editor or IDE. Having to switch between a command-line tool and editor can slow down the development process.

Gradle doesn’t leave you hanging. With the help of plugins, you can generate project files for various IDEs and editors. The generated project files contain the metadata needed to conveniently open a project in an IDE with the correct setup. We discussed how to use these plugins in the context of your To Do application to create project files for Eclipse, IntelliJ IDEA, and Sublime Text. This metadata is mainly derived from the default build script configuration but can be customized to fit individual needs.

Popular Java IDE vendors realized the need for first-class Gradle support. The IDEs SpringSource STS, IntelliJ IDEA, and NetBeans provide sufficient tooling for opening a Gradle project by pointing them to a build script. Once the project is opened in the tool, a developer is able to manage dependencies, use Gradle DSL code completion, and execute tasks from within the IDE.

The tooling API forms the foundation for integrating Gradle with many of the IDEs we discussed. It allows for executing Gradle tasks, while at the same time monitoring and querying the running build. You learned that the tooling API can be used for implementing integration tests for a Gradle build script under real-world conditions.

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

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