Chapter 29. The IDEA Plugin

The IDEA plugin generates files that are used by IntelliJ IDEA, thus making it possible to open the project from IDEA (File - Open Project). Both external dependencies (including associated source and javadoc files) and project dependencies are considered.

What exactly the IDEA plugin generates depends on which other plugins are used:

Table 29.1. IDEA plugin behavior

PluginDescription
NoneGenerates an IDEA module file. Also generates an IDEA project and workspace file if the project is the root project.
Java Adds Java configuration to the module and project files.

One focus of the IDEA plugin is to be open to customization. Each task provides a standardized set of hooks for adding and removing content from the generated files.

29.1. Usage

To use the IDEA plugin, include this in your build script:

Example 29.1. Using the IDEA plugin

build.gradle

apply plugin: 'idea'

The IDEA plugin adds a number of tasks to your project. The main tasks that you will use are the idea and cleanIdea tasks.

29.2. Tasks

The IDEA plugin adds the tasks shown below to a project.

Table 29.2. IDEA plugin - Tasks

Task name Depends on Type Description
idea ideaProject, ideaModule, ideaWorkspace - Generates all IDEA configuration files
cleanIdea cleanIdeaProject, cleanIdeaModule, cleanIdeaWorkspace Delete Removes all IDEA configuration files
cleanIdeaProject - Delete Removes the IDEA project file
cleanIdeaModule - Delete Removes the IDEA module file
cleanIdeaWorkspace - Delete Removes the IDEA workspace file
ideaProject - GenerateIdeaProject Generates the .ipr file. This task is only added to the root project.
ideaModule - GenerateIdeaModule Generates the .iml file
ideaWorkspace - GenerateIdeaWorkspace Generates the .iws file. This task is only added to the root project.

Table 29.3. IdeaModule task

Property Type Default Value Default Value with Java Plugin Description
moduleDir File projectDir projectDir The content root directory of the module. Must not be null.
outputFile File projectDir/<project.name>.iml - The .iml file. Used to look for existing files and as the target for generation. Must not be null.
inheritOutputDirs Boolean null null If null, the value in the existing or default module file is used (the default file uses true). If true, the module output directories will be located below the project output directories. If false, the directories specified with the sourceDirs and testSourceDirs properties are used.
sourceDirs Set<File> empty set The source directories of sourceSets.main The directories containing the production sources. Must not be null.
testSourceDirs Set<File> empty set The source directories of sourceSets.test The directories containing the test sources. Must not be null.
excludeDirs Set<File> empty set - The directories to be excluded by IDEA. Must not be null.
outputDir File null null The IDEA output directory for the production sources. If null, no entry is created.
testOutputDir File null null The IDEA output directory for the test sources. If null, no entry is created.
javaVersion String null - If null, the value of the existing or default .ipr file is used (the default file uses inherited). If set to inherited, the project SDK is used. Otherwise, the SDK for the corresponding value of java version is used.
downloadSources boolean true - Whether to download and add source Jars associated with the dependency Jars.
downloadJavadoc boolean false - Whether to download and add javadoc Jars associated with the dependency Jars.
scopes Map [:] COMPILE(compile), RUNTIME(runtime - compile), TEST(testRuntime - runtime) The keys of this map are the IDEA scopes. Each key points to another map that has two keys, plus and minus. The values of those keys are sets of Configuration objects. The files of the plus configurations are added minus the files from the minus configurations.
variables Map<String, File> [:] - The variables to be used for replacing absolute paths in the .iml file. For example, you might add a GRADLE_USER_HOME variable to point to the Gradle user home directory.

Table 29.4. IdeaProject task

Property Type Default Value Default Value with Java Plugin Description
subprojects Set<Project> rootProject.allprojects - The subprojects that should be mapped to modules in the .ipr file. The subprojects will only be mapped if the IDEA plugin has been applied to them.
outputFile File projectDir/<project.name>.ipr - The .ipr file. Used to look for existing files and as the target for generation. Must not be null.
javaVersion String 1.6 - The Java version used for defining the project SDK.
wildcards Set<String> ['!?*.java', '!?*.groovy'] - The wildcard resource patterns. Must not be null.

Table 29.5. IdeaWorkspace task

Property Type Default Value Default Value with Java Plugin Description
outputFile File projectDir/<project.name>.iws - The .iws file. Used to look for existing files and as the target for generation. Must not be null.

29.3. Customizing the generated files

All IDEA tasks provide the same hooks and behavior for customizing the generated content. However, the workspace file can effectively only be manipulated via the withXml hook, because its corresponding domain object is essentially empty.

The tasks recognize existing IDEA files, and merge them with the generated content.

29.3.1. Merging

Sections of existing IDEA files that are also the target of generated content will be amended or overwritten, depending on the particular section. The remaining sections will be left as-is.

29.3.1.1. Disabling merging with a complete overwrite

To completely overwrite existing IDEA files, execute a clean task together with its corresponding generation task, for example gradle cleanIdea idea (in that order). If you want to make this the default behavior, add idea.dependsOn(cleanIdea) to your build script. This makes it unnecessary to execute the clean task explicitly.

Complete overwrite works equally well for individual files, for example by executinggradle cleanIdeaModule ideaModule.

29.3.2. Hooking into the generation lifecycle

The IDEA plugin provides domain classes modeling the sections of the IDEA files that are autogenerated by Gradle. The generation lifecycle is as follows:

  1. If there is an existing file, its whole XML content is parsed and stored in memory; otherwise, a default file is used in its place
  2. The domain objects are populated with the relevant content of the existing file
  3. The beforeConfigured hook is executed
  4. The domain objects are populated with content from Gradle's build model, which may require merging with content from the existing file
  5. The whenConfigured hook is executed
  6. All sections modeled by the domain objects are removed from the in-memory XML representation
  7. The domain objects inject their content into the in-memory XML representation
  8. The withXml hook is executed
  9. The in-memory XML representation is written to disk

The following table lists the domain objects used for each of the IDEA task types:

Table 29.6. Task Hooks

Task type beforeConfigured { arg -> } argument type whenConfigured { arg -> } argument type withXml { arg -> } argument type
GenerateIdeaProject Project Project XmlProvider
GenerateIdeaModule Module Module XmlProvider
GenerateIdeaWorkspace Workspace Workspace XmlProvider

29.3.2.1. Partial overwrite of existing content

A complete overwrite causes all existing content to be discarded, thereby losing any changes made directly in the IDE. The beforeConfigured hook makes it possible to overwrite just certain parts of the existing content. The following example removes all existing dependencies from the Module domain object:

Example 29.2. Partial Overwrite for Module

build.gradle

ideaModule {
    beforeConfigured { module ->
        module.dependencies.clear()
    }
}


The resulting module file will only contain Gradle-generated dependency entries, but not any other dependency entries that may have been present in the original file. (In the case of dependency entries, this is also the default behavior.) Other sections of the module file will be either left as-is or merged. The same could be done for the module paths in the project file:

Example 29.3. Partial Overwrite for Project

build.gradle

ideaProject {
    beforeConfigured { project ->
        project.modulePaths.clear()
    }
}


29.3.2.2. Modifying the fully populated domain objects

The whenConfigured hook allows to manipulate the fully populated domain objects. Often this is the preferred way to customize IDEA files. Here is how you would export all the dependencies of an IDEA module:

Example 29.4. Export Dependencies

build.gradle

ideaModule {
    whenConfigured { module ->
        module.dependencies*.exported = true
    }
}


29.3.2.3. Modifying the XML representation

The withXmlhook allows to manipulate the in-memory XML representation just before the file gets written to disk. Although Groovy's XML support makes up for a lot, this approach is less convenient than manipulating the domain objects. In return, you get total control over the generated file, including sections not modeled by the domain objects.

Example 29.5. Customizing the XML

build.gradle

ideaProject {
    withXml { provider ->
        provider.node.component.find { it.@name == 'VcsDirectoryMappings' }.mapping.@vcs = 'Git'
    }
}


29.4. Further things to consider

The paths of the dependencies in the generated IDEA files are absolute. If you manually define a path variable pointing to the Gradle dependency cache, IDEA will automatically replace the absolute dependency paths with this path variable. If you use such a path variable, you need to tell the ideaModule task the name of this variable, so that it can do a proper merge without creating duplicates.