IntelliJ IDEA from JetBrains is another IDE we can use to develop applications. Gradle has the IDEA plugin to generate the project files for IntelliJ IDEA. This means we can simply open the project in IntelliJ IDEA. The dependencies are set correctly so as to compile the project in the IDE. In this section, we will see how we can generate those files and customize file generation.
IntelliJ IDEA supports a folder-based and file-based format for the project files. The IDEA plugin generates files for the file-based format. The file format for the project files is XML. The workspace project file has the extension .iws
and contains personal settings. The project information is stored in a file with extension .ipr
. The project file can be saved in a version control system, because it doesn't have reference to local paths. The workspace project file has a lot of personal settings and shouldn't be put in a version control system.
For a Java project, we have a third project file with the exension .iml
. This file contains dependency references with local path locations. We shouldn't put this file in a version control system. The IDEA plugin can just, like the Eclipse plugin, download associated source files for a dependency. We can also configure and download the associated Javadoc files. The IDEA plugin works together with the Java plugin. If we have a Gradle build file and apply both the Java and IDEA plugins, a specific Java configuration is added to the project files.
Let's create an example build file and apply the IDEA plugin, as shown in the following code snippet:
apply plugin: 'java' apply plugin: 'idea' version = 1.0 sourceCompatibility = 1.6 targetCompatibility = 1.6 description = 'Sample project' ext { slf4jVersion = '1.6.6' slf4jGroup = 'org.slf4j' } configurations { extraLib } repositories { mavenCentral() } dependencies { testCompile 'junit:junit:4.8' extraLib "$slf4jGroup:slf4j-api:$slf4jVersion", "$slf4jGroup:slf4j-simple:$slf4jVersion" }
First, we execute the tasks
task and see which tasks are added by the plugin,as follows:
$ gradle tasks --all ... IDE tasks --------- cleanIdea - Cleans IDEA project files (IML, IPR) cleanIdeaModule cleanIdeaProject idea - Generates IDEA project files (IML, IPR, IWS) ideaModule - Generates IDEA module files (IML) ideaProject - Generates IDEA project file (IPR) ideaWorkspace - Generates an IDEA workspace file (IWS) ...
We have an idea
task that is dependent on the following three other tasks: ideaWorkspace
, ideaModule
, and ideaProject
. Each of these tasks can generate a project file. To remove the module and project files, we can execute the cleanIdeaModule
and cleanIdeaProject
tasks or simply the cleanIdea
task. There is no cleanIdeaWorkspace
task, because the workspace file contains personal settings. These settings are probably set via the user interface of IntelliJ IDEA and shouldn't be removed by a Gradle task.
When we run the idea
task from the command line and look at the output which is as follows, we see that all the tasks are executed and we now have three project files:
$ gradle idea :ideaModule :ideaProject :ideaWorkspace :idea BUILD SUCCESSFUL Total time: 4.477 secs
The IDEA plugin has several ways to customize the configuration in the generated files. The plugin will look in the project settings and use the information in the generated files. For example, we can set the source and target compatibility versions in our Gradle project and the plugin will use them to set a correct value in the generated project file.
We can use a DSL to change the configuration information before the file is generated. Gradle also offers hooks where we can manipulate model objects before and after the project information and DSL configuration is applied. To change the generated XML structure, we can implement the withXml
hook. We can alter the XML just before it is written to disk. To change the contents of the workspace file, we should use the withXml
hook. The workspace file has an empty model object and has no DSL, because the contents are very specific and they contain a lot of personal settings.
The IDEA plugin adds a new idea configuration script block that is used to change the project files' contents. For the module and project files, we can use a DSL to set the configuration settings. Each file has its own configuration script block.
For module file generation, we can change the name of the file. But, it is best to leave it unchanged. Gradle will make sure the file names are unique within a multi-project build. IntelliJ IDEA requires that the module names be unique for a multi-module project.
IntelliJ IDEA has several scopes for dependencies. We can customize which dependency configuration apply to which scope. The following table shows the default mapping of IntelliJ IDEA scopes with Gradle dependency configurations:
IntelliJ IDEA scope |
Gradle configuration |
---|---|
Compile |
|
Runtime |
|
Test |
|
Provided |
Not set |
Each scope has a plus
and minus
key. We can add additional configurations using the plus
key and remove configurations with the minus
key.
In the following example build file, we see the different options and methods of the DSL used to change the project file contents:
apply plugin: 'java' apply plugin: 'idea' idea { project { // Set JDK name. Default is from Java version // used to run Gradle. jdkName = '1.6' // Set Java language level for the project. // Default value is project.sourceCompatibility. languageLevel = '1.6' // Or JDK_1_6 // For multi-project builds we can define other modules. // Default value is project.allprojects*.idea.module. modules = project(':other').idea.module // Set resource wildcard pattern. // Default value is ['!?*.java', '!?*.groovy'] wildcards += '!?*.xsd' } }
The following example build file shows some of the options we can use to change the module file:
apply plugin: 'java' apply plugin: 'idea' configurations { extraLib } sourceSets { api } idea { module { // Download associated Javadoc files for dependencies. // Default value is false. downloadJavadoc = true // Download associated source files for dependencies. // Default value is true. downloadSources = true // Set which directories to exclude. excludeDirs += file('.settings') // Set specific JDK for this module, or use the value 'inherited' // to use project JDK. Default value is 'inherited'. jdkName = 'inherited' // Directory with the source files. // Default value is project.sourceSets.main.allSource sourceDirs += project.sourceSets.api.allSource // Directory with the test source files. // Default value is project.sourceSets.test.allSource testSourceDirs += project.sourceSets.api.allSource // Set configurations for the IntelliJ IDEA scopes. scopes.COMPILE.plus += configurations.extraLib scopes.TEST.minus += configurations.extraLib } }
With the merge hooks, we can access the model objects and manipulate them to customize file generation. In the following table, we can see the type of argument that is passed to the beforeMerged
and whenMerged
hooks:
Model |
Merge hook argument |
Description |
---|---|---|
Project |
|
Model object with properties for project file generation. |
Module |
|
Model object with properties for module file generation. |
The project
script block has an ipr
script block that we must use to define the beforeMerged
and whenMerged
hooks. The module
script block has the iml
configuration script block to define those hooks.
In the following example build file, we see some of the things we can do by using the merge hooks:
apply plugin: 'java' apply plugin: 'idea' version = 1.0 description = 'Sample project' repositories { mavenCentral() } dependencies { testCompile 'junit:junit:4.8' } idea { project { ipr { beforeMerged { iprProject -> iprProject.wildCards.removeAll() } whenMerged { iprProject -> iprProject.wildCards.add '!?*.xsd' } } } module { iml { beforeMerged { imlModule -> imlModule.outputDir = null } whenMerged { imlModule -> imlModule.jdkName = '1.6' module.dependencies*.exported = true imlModule.excludeFolders.add file('.svn') } } } }
At the lowest level, we can manipulate the XML before it is written to disk. For workspace file configuration changes, this is the best way. We can also use it for the project and module files. We must implement a closure with the withXml
hook to customize the XML structure. The closure has a single argument of type org.gradle.api.XmlProvider
. We can use the
asNode()
method to get a Groovy groovy.util.Node
object. This is the easiest way to manipulate the XML. The asString()
method returns a StringBuilder
object and the asElement()
returns an org.w3c.dom.Element
object.
In the following example build file, we make some changes to the XML for the project, module, and workspace files:
apply plugin: 'java' apply plugin: 'idea' idea { project { ipr { withXml { xml -> def projectRoot = xml.asNode() projectRoot.component.find { it.@name == 'ProjectRootManager' }.@'assert-keyword' = true def javadoc = projectRoot.component.find { it.@name == 'JavadocGenerationManager' } javadoc.option.find { it.@name == 'OPEN_IN_BROWSER' }.@value = false } } } module { iml { withXml { xml -> def moduleRoot = xml.asNode() def facetManager = moduleRoot.component.find { it.@name == 'FacetManager' } facetManager.plus { facet(type: 'Spring', name: 'Spring') { configuration { fileset(id: 'fileset1', name: 'XML Application Context') { file 'file://$MODULE_DIR$/src/main/resources/applicationContext.xml' } } } } } } } workspace { iws { withXml { xml -> def workspaceRoot = xml.asNode() def coverageViewManager = workspaceRoot.component.find { it.@name == 'CoverageViewManager' } coverageViewManager.option.find { it.@name == 'myFlattenPackages' }.@value = 'false' } } } }
18.191.150.231