Failing on Unwanted Class Imports

July 01, 2017

Often it is desirable to avoid a specific class without banning its entire package. java.util.Date is a good example of this, as most of its methods are deprecated, but rejecting java.util would leave the user unable to reference common classes like java.util.List.

As of Checkstyle 7.8, we can fail the build when unwanted classes are imported through Gradle’s built-in checkstyle plugin. Setup is different for solo-project and multi-project builds. See the following links for a git diff of what is needed to enable this behavior:

solo-project
2307a31b
multi-project
66667330

Context

If I have a project that is committed to using java.time, using java.util.Date will only ever be an accident that can cause bugs and create confusion in the future. Gradle’s checkstyle plugin and the IllegalImport rule can help me formalize this intention as part of my build.

Solo-Project Setup

We’ll start with a simple example project that has imported a method from our unwanted package: sghill/fail-unwanted-class-imports.

Apply the plugin:

apply plugin: 'checkstyle'

The bundled version of the plugin is not recent enough, so we’ll need to upgrade that by specifying the dependency of at least 7.8 on the checkstyle configuration:

checkstyle {
    toolVersion '7.8.2'
}

The plugin is looking for configuration in ${project.projectDir}/config/checkstyle/checkstyle.xml by default.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC
        "-//Puppy Crawl//DTD Check Configuration 1.3//EN"
        "http://www.puppycrawl.com/dtds/configuration_1_3.dtd">

<module name="Checker">
    <module name="TreeWalker">
        <module name="IllegalImport">
            <property name="illegalClasses" value="java.util.Date"/>
        </module>
    </module>
</module>

Now running ./gradlew build fails our new :checkstyleTest task:

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':checkstyleTest'.
> Checkstyle rule violations were found. See the report at: file:///Users/sghill/code/build-well/fail-unwanted-class-imports/build/reports/checkstyle/test.html

Multi-Project Setup

We’re going to reuse the solo-project configuration in the same location for our multi-project setup. The default checkstyle file path is relative to the project instead of the rootProject, so we’ll need to do some task configuration. This is the way to share a checkstyle configuration:

allprojects {
    apply plugin: 'checkstyle'

    tasks.withType(Checkstyle) {
        def path = "${rootProject.projectDir}/config/checkstyle/checkstyle.xml"
        config resources.text.fromFile(path)
    }
}

Now running ./gradlew build gives us an errors from foundation:

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':foundation:checkstyleMain'.
> Checkstyle rule violations were found. See the report at: file:///Users/sghill/code/build-well/fail-unwanted-classes/foundation/build/reports/checkstyle/main.html

Versions

This example has been tested against the following versions:

Date Gradle Checkstyle Solo-Project Multi-Project
2017-07-01 4.0 7.8.2 output output
2017-07-01 3.5.1 7.8.2 output output
2017-07-01 3.4.1 7.8.2 output output
2017-07-01 3.3 7.8.2 output output

Profile picture

Written by @sghill, who works on build, automated change, and continuous integration systems.