[TUT] Create your own CheckStyle check

Android code is just like any Java system, you need to write tests and have automated code review checks. CheckStyle is a way of double checking your Java code.

Checkstyle is a development tool to help programmers write Java code that adheres to a coding standard. It automates the process of checking Java code to spare humans of this boring (but important) task. This makes it ideal for
projects that want to enforce a coding standard.

Below I outline how you can write your own custom CheckStyle checks so you can tailor CheckStyle to the way you work. This example has a check to point out the use of Hungarian Notation, specifically the ‘m’ prefix for fields in your class. This is a dated practice and has no place in the modern IDE.

What we are going to do:

  • Create a test project with the errors we want to point out
  • Create a project that will house our custom checks
  • Hook up our test project to run checkstyle
  • Run our custom check against the Test Project

The code does most the explanation here, note that this uses Maven as a build tool. You don’t need to use Maven, you could: create the projects, add checkstyle to the build path and run from the command line.

To create a custom checkstyle check you extend the puppycrawl.CheckStyle ‘Check’ class. Here we’ve split the check itself into another class that uses a reg ex to find member variables with a leading ‘m’:

AntiHungarianCheck.java

package com.blundell.checks;

import com.puppycrawl.tools.checkstyle.api.*;

public class AntiHungarianCheck extends Check {

    private static final String CATCH_MSG = "Hungarian notation belongs in the 90's. " +
    		                                "Don't prefix member variables with 'm'. " +
    		                                "Use your IDE's shiny colors. Culprit was: ";

    private final HungarianNotationMemberDetector detector = new HungarianNotationMemberDetector();

    @Override
    public int[] getDefaultTokens() {
        return new int[] {TokenTypes.VARIABLE_DEF};
    }

    @Override
    public void visitToken(DetailAST aAST) {
        String variableName = findVariableName(aAST);
        if (itsAFieldVariable(aAST) && detector.detectsNotation(variableName)) {
            reportStyleError(aAST, variableName);
        }
    }

    private String findVariableName(DetailAST aAST) {
        DetailAST identifier = aAST.findFirstToken(TokenTypes.IDENT);
        return identifier.toString();
    }

    private boolean itsAFieldVariable(DetailAST aAST) {
        return aAST.getParent().getType() == TokenTypes.OBJBLOCK;
    }

    private void reportStyleError(DetailAST aAST, String variableName) {
        log(aAST.getLineNo(), CATCH_MSG + variableName);
    }

}

HungarianNotationMemberDetector.java

package com.blundell.checks;

import java.util.regex.Pattern;

class HungarianNotationMemberDetector {

    private Pattern pattern = Pattern.compile("m[A-Z0-9].*");

    public boolean detectsNotation(String variableName) {
        return pattern.matcher(variableName).matches();
    }
}

Thanks to Gnorsilva for the RegEx and adding unit testing.

The key point to this process is getting checkstyle to use your custom checks jar file.

Checkstyle needs to know what checks you want to run, for this example we just run our 1 custom check, but otherwise you would append the custom check to this list.

checkstyle-config.xml

<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
    "-//Puppy Crawl//DTD Check Configuration 1.2//EN"
    "https://www.puppycrawl.com/dtds/configuration_1_2.dtd">

<module name="Checker">
  <module name="TreeWalker">
    <!-- Blundell specific checks -->
    <module name="com.blundell.checks.AntiHungarian" />
  </module>
</module>

Then you need to tell CheckStyle to use this config, if your running from the command line it would be slightly different, but with Maven and the latest version of CheckStyle it’s like this:

<properties>
    <checkstyle.config.location>properties/checkstyle-configuration.xml</checkstyle.config.location>
  </properties>

With maven you declare that you want to use the CheckStyle plugin and that this plugin needs to use your own check jar.

<plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-checkstyle-plugin</artifactId>
        <version>2.9.1</version>
        <dependencies>
          <dependency>
            <groupId>com.blundell</groupId>
            <artifactId>blundell-checkstyle-checks</artifactId>
            <version>1.0</version>
          </dependency>
        </dependencies>
      </plugin>

Now all you need to do is run ‘mvn checkstyle:checkstyle’ and your custom check will be ran.

Running checkstyle creates a report which can be found in the TestProject/target directory, it looks something like this:

CheckStyle Report

More information can be found in the ReadMe of the GitHub project.

Sources and example:

Create Your Own CheckStyle Check : GitHub