Hi all, my name is Hubert A. Klein Ikkink. Not a very common name, right? To make things easier I just picked the first letters of my firstname and surname and came up with haki. So there you have it, now I am also known as Mr. Haki or mrhaki for short. You can read more blog postings at www.mrhaki.com. I am a passionate Groovy and Java developer based in Tilburg, The Netherlands. My goal is to write clean, elegant, user-centered and high quality software. You can find me on Google+ and Twitter. Hubert is a DZone MVB and is not an employee of DZone and has posted 164 posts at DZone. You can read more from them at their website. View Full User Profile

Gradle Goodness: Customize IDEA Project File Generation

09.30.2012
| 3316 views |
  • submit to reddit

With the Gradle IDEA plugin we can generate JetBrains IntelliJ IDEA project files. The plugin uses defaults from our project to generate the files. If we also apply the Java plugin to our project then the Java settings for the project files are generated. We can customize the file generation in several ways. The most low level method is using the withXml hook. With this hook we have access to the XML before the file is written to disk. Here we can add or change XML elements and attribute values.

We use a closure as argument for the withXml hook and Gradle adds a XmlProvider object as argument. The easiest way to manipulate the XML is getting a groovy.util.Node from the XmlProvider. We also can get a DOM Element or StringBuilder to work with.

In the following example build file we change the contents of the IDEA project file (with extension .ipr). We change the output directory of the JavaDoc tool. We use Groovy syntax to find the JavadocGenerationManager which is automatically added, because we have the Java plugin in our build file. We also change the Encoding component or create it when it doesn't exist:

apply plugin: 'java'
apply plugin: 'idea'

idea {
    project {
        // Here we customize the .ipr file generation.
        ipr {
            // XML hook to customize the XML before
            // it is written to disk
            withXml { xmlProvider ->
                // Get root node.
                def project = xmlProvider.asNode()

                customizeJavaDoc project
                customizeEncoding project
            }
        }
    }
}

/* Customize JavadocGenerationManger component */
def customizeJavaDoc(project) {
    def javaDocGenerationManager = findComponent(project, 'JavadocGenerationManager')
    changeOption javaDocGenerationManager, 'OUTPUT_DIRECTORY', '$PROJECT_DIR$/out/javadoc'
}

/* Search component with given name */
def findComponent(project, name) {
    project.component.find { it.@name == name }
}

/* Set value for option node with given name */
def changeOption(node, name, value) {
    node.option.find { it.@name == name }.@value = value
}

/* Customize Encoding component */
def customizeEncoding(project) {
    def encoding = findComponent(project, 'Encoding')

    if (encoding) {
        // Change existing node.
        encoding.@useUTFGuessing = true
        encoding.@native2AsciiForPropertiesFiles = true
        encoding.@defaultCharsetForPropertiesFiles = 'UTF-8'
    } else {
        // Create new node with default values.
        project.appendNode 'Encoding', [useUTFGuessing: true, native2AsciiForPropertiesFiles: true, defaultCharsetForPropertiesFiles: 'UTF-8']
    }
}

To add a XML structure we can use Groovy's NodeBuilder. With the NodeBuilder we use builder syntax to define the structure. The result is a Node object that we can use to insert in the XML that is used to generate the IDEA project file. In the following example build.gradle file we create a new inspection profile with a customized Spelling inspection:

apply plugin: 'java'
apply plugin: 'idea'

idea {
    project {
        // Here we customize the .ipr file generation.
        ipr {
            // XML hook to customize the XML before
            // it is written to disk
            withXml { xmlProvider ->
                // Get root node.
                def project = xmlProvider.asNode()
                customizeSpellingInspection(project)
            }
        }
    }
}

/* Change or add spelling inspection */
def customizeSpellingInspection(project) {
    def inspections = findComponent(project, 'InspectionProjectProfileManager')
    
    if (inspections) {
        // Update existing profiles to disable spell checking
        // for processCode and processLiterals.
        def spellChecking = inspections.profiles.profile.option.inspection_tool.find { it.@class == 'SpellCheckingInspection'}
        if (spellChecking) {
            ['processCode', 'processLiterals'].each { optionName ->
                spellChecking.option.find { it.@name == optionName }.@value = 'false'
            }
        }
    } else {
        // Create new InspectionProjectProfileManager component. 
        inspections = project.appendNode('component', [name: 'InspectionProjectProfileManager'])

        // Use NodeBuilder to build profiles XML structure.
        def builder = new NodeBuilder()
        def profiles = builder.profiles {
            profile(version: '1.0', is_locked: false) {
                option(name: 'myName', value: 'Default Inspections')
                option(name: 'myLocal', value: false)
                inspection_tool(class: 'SpellCheckingInspection', enabled: true, level: 'TYPO', enabled_by_default: true) {
                    option(name: 'processCode', value: false)
                    option(name: 'processLiterals', value: false)
                    option(name: 'processComments', value: true)
                }
            }
        }
        // Add result from NodeBuilder
        inspections.append profiles

        // Extra nodes added with appendNode() method.
        inspections.appendNode 'option', [name: 'PROJECT_PROFILE', value: 'Default Inspections']
        inspections.appendNode 'option', [name: 'USE_PROJECT_PROFILE', value: true]
        inspections.appendNode 'version', [value: "1.0"]
    }
}

/* Search component with given name */
def findComponent(project, name) {
    project.component.find { it.@name == name }
}

(Gradle 1.2 is used for samples)

 

Published at DZone with permission of Hubert Klein Ikkink, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)