Search

Dark theme | Light theme

March 3, 2016

Gradle Goodness: Adding Custom Extension To Tasks

We can add extensions to our project in Gradle to extend the build script with extra capabilities. Actually we can add extensions to any object in Gradle that implements the ExtensionAware interface. The Task interface for example extends the ExtensionAware interface so we can add custom extensions to Gradle tasks as well. Inside a task configuration we can then use that extension.

In the following build script we use a custom extension for JavaCompile tasks to configure the compiler -Xlint arguments. The extension is added via the plugin com.mrhaki.gradle.JavaCompilerLintPlugin. First we take a look ate the extension class. This is a POGO for configuring the compiler arguments with -Xlint options:

// File: buildSrc/src/main/groovy/com/mrhaki/gradle/JavaCompilerLintExtension.groovy
package com.mrhaki.gradle

/**
 * Extension class for use with JavaCompile tasks
 * to set -Xlint options.
 */
class JavaCompilerLintExtension {

    Boolean cast
    Boolean classfile
    Boolean deprecation
    Boolean depAnn
    Boolean divzero
    Boolean empty
    Boolean fallthrough
    Boolean finallyblocks
    Boolean options
    Boolean overrides
    Boolean path
    Boolean processing
    Boolean rawtypes
    Boolean serial
    Boolean staticref
    Boolean tryblocks
    Boolean unchecked
    Boolean varargs

    void enableAll() {
        cast = true
        classfile = true
        deprecation = true
        depAnn = true
        divzero = true
        empty = true
        fallthrough = true
        finallyblocks = true
        options = true
        overrides = true
        path = true
        processing = true
        rawtypes = true
        serial = true
        staticref = true
        tryblocks = true
        unchecked = true
        varargs = true
    }

    /**
     * Create list of compiler -Xlint arguments.
     * 
     * @return List of -Xlint compiler arguments.
     */
    List<String> asCompilerArgs() {
        final List<String> optionArgs = []
        optionArgs << optionArg('cast', cast)
        optionArgs << optionArg('classfile', classfile)
        optionArgs << optionArg('deprecation', deprecation)
        optionArgs << optionArg('dep-ann', depAnn)
        optionArgs << optionArg('divzero', divzero)
        optionArgs << optionArg('empty', empty)
        optionArgs << optionArg('fallthrough', fallthrough)
        optionArgs << optionArg('finally', finallyblocks)
        optionArgs << optionArg('options', options)
        optionArgs << optionArg('overrides', overrides)
        optionArgs << optionArg('path', path)
        optionArgs << optionArg('processing', processing)
        optionArgs << optionArg('rawtypes', rawtypes)
        optionArgs << optionArg('serial', serial)
        optionArgs << optionArg('static', staticref)
        optionArgs << optionArg('try', tryblocks)
        optionArgs << optionArg('unchecked', unchecked)
        optionArgs << optionArg('varargs', varargs)

        // filter null values.
        final List<String> compilerArgs = optionArgs.findAll() 
        return compilerArgs
    }

    /**
     * Create -Xlint compile option if option is set. 
     * 
     * @param name Name of the -Xlint compile option.
     * @param enable Set option argument as -Xlint:option if true, otherwise as -Xlint:-option if false.
     * @return Null if enable is null, otherwise a valid -Xlint compiler option.
     */
    private String optionArg(final String name, final Boolean enable) {
        if (enable != null) {
            final String option = enable ? name : "-$name"
            return "-Xlint:$option"
        }
        return null
    }
}

Next we have a plugin class that registers the extension with the name lint on all JavaCompile tasks in our project:

// File: buildSrc/src/main/groovy/com/mrhaki/gradle/JavaCompilerLintPlugin.groovy
package com.mrhaki.gradle

import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.tasks.compile.JavaCompile

/**
 * Plugin for applying a custom extension to 
 * JavaCompile tasks for configuring the 
 * -Xlint options.
 */
class JavaCompilerLintPlugin implements Plugin<Project> {
    
    void apply(final Project project) {
        
        // For all JavaCompile tasks we add 
        // a custom extension with the name lint
        // for configuring -Xlint options.
        project.tasks.withType(JavaCompile) { task ->
            
            // Let Gradle create a new extension.
            // Users can configure a compile task 
            // from the Java plugin like:
            // compileJava {
            //   lint {
            //     cast = true
            //   }
            // }
            JavaCompilerLintExtension taskExtension =
                    task.extensions.create('lint', JavaCompilerLintExtension)

            // Use options set via the lint extension
            // and assign them to the options.compilerArgs
            // property.
            // We do this in doFirst because the options are not
            // set yet at the Gradle configuration phase.
            task.doFirst {
                options.compilerArgs = taskExtension.asCompilerArgs()
            }
        }
    }
    
}

We have everything ready, so let's use the plugin in our Java project:

// File: build.gradle
apply plugin: 'java'

apply plugin: com.mrhaki.gradle.JavaCompilerLintPlugin

repositories {
    jcenter()
}

dependencies {
    testCompile 'junit:junit:4.11'
}

compileJava {
    // Here we use the custom
    // task extension. The closure
    // delegates to JavaCompilerLintExtension. 
    lint {
        enableAll()
        empty = false
        depAnn = false
    }
}

compileTestJava {
    // All JavaCompile task have the 
    // lint extension.
    lint {
        cast = true
    }
}

Written with Gradle 2.11.