Browse DevX
Sign up for e-mail newsletters from DevX


Maintain Better Coding Standards with Ease Using Checkstyle : Page 3

Coding standards are a time-honored and widely respected programming best practice. However, they are not always easy to put into action. Find out how Checkstyle can help you define and enforce a set of coding standards and promote good and consistent programming habits across your team.




Building the Right Environment to Support AI, Machine Learning and Deep Learning

Customizing Checkstyle Coding Standards in XML
Under the hood, a Checkstyle configuration file is a standard XML file which defines a set of modules that are to be used to verify source code. Each module is specialized in one particular kind of coding standard or best practice.

Modules are organized hierarchically: The root module is always the "Checker" module, which contains other modules. Modules can also contain sub-modules. This is notably the case of the "TreeWalker" module, which parses a Java source file and then lets sub-modules verify different aspects of the parse tree. In fact, the majority of Checkstyle modules are sub-modules of the "TreeWalker" module. Here is an excerpt from a simple Checkstyle configuration file:

<module name="Checker"> <module name="TreeWalker"> <module name="JavadocMethod"/> <module name="JavadocVariable"/> <property name="scope" value="protected"/> </module> <module name="AvoidStarImport"/> </module> <module name="PackageHtml"/> </module>

Module behavior can be customized using properties. Each module has a set of properties with default values. To override a property, you just add a property tag in the body of the module tag. For example, for the "LineLength" module the default maximum line length is 80 characters. If you want to check for lines longer than 70 characters instead, you would set the "max" property, as follows:

<module name="LineLength"> <property name="max" value="70"/> </module>

The severity property can be applied to any module, and is used to determine the type of message that will be displayed. To deactivate a module, for example, set the severity to "ignore":

<module name="LineLength"> <property name="severity" value="ignore"/> <property name="max" value="70"/> </module>

Most modules perform well using the default configuration. The "JavadocType" module checks class and interface Javadoc comments. To activate this module with the default values, you just declare the module in the configuration file (it must be nested inside the "TreeWalker" module):

<module name="JavadocType"/>

By default the @author tag is not required. For your project or company, you may decide to make it mandatory. If so, you would also define the "authorFormat" property for this module as follows (in this case, any non-null string will do):

<module name="JavadocType"> <property name="authorFormat" value="\S"/> </module>

Many modules, such as naming conventions use regular expressions. For example, here is a stricter version of the package naming convention, where only lower-case letters and digits are authorized in package names:

<module name="PackageName"> <property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$"/> </module>

Many companies and projects use a standard file header convention. Checkstyle offers many ways to enforce this. For simple cases, you can write a header template, where some lines are fixed and others may be modified by the developer. Suppose your company standards impose a boxed-style comment with a copyright line at the bottom, as shown here:

//////////////////////////////////////////////////////////////////// // My Project Title // A description of this file goes here. // // Copyright (C) 2006 My Company ////////////////////////////////////////////////////////////////////

One easy way to do this is to define a header template called java.header, which would contain the above text, and then to indicate which lines may be modified:

<module name="Header"> <property name="headerFile" value="java.header"/> <property name="ignoreLines" value="2, 3, 4"/> </module> Suppose that all you need to do is to put a copyright line at the top of each file: // Copyright (C) 2006 MyCompany // All rights reserved

However, the year needs to change each year. To do this, you can define an inline regular expression using the RegexpHeader module, as shown here:

<module name="RegexpHeader"> <property name="header" value="^// Copyright \(C\) \d\d\d\d My Company$\n^// All rights reserved$"/> </module>

You can also define the header as a more complicated regular expression in an external file. Suppose your company or project standards require a file header containing dynamic elements coming from the source configuration system, as in the following example:

//////////////////////////////////////////////////////////////////// // My Project Title // File: $Id$ // A short description goes here // // Last modified $Date$ by $Author $ // Copyright (C) 2006 My Company ////////////////////////////////////////////////////////////////////

This can be configured using the RegexpHeader module and an external file template (called "java.header" in this example):

<module name="RegexpHeader"> <property name="headerFile" value="java.header"/> </module>

The java.header file in this case would look like this:

^//////////////////////////////////////////////////////////////////// ^// My Project Title ^// File: \$Id.*\$$ ^//.*$ ^// ^// Last modified \$Date.*\$ by \$Author.*\$$ ^// Copyright \(C\) \d\d\d\d My Company ^////////////////////////////////////////////////////////////////////

There are many other modules that can be activated and configured. Check out the Checkstyle documentation for further details.

Suppressing Checkstyle Tests
There will be times when you come across a genuine reason for violating a coding standard for a particular section of code. For example, the following code extracts the list of students in each percentile:

for (int i = 1; i < 100; i++) { List<Student> students = extractCentile(i, examResults); …. }

In this context, the use of the value 100, for example, is clear, and there is little added value in replacing it by a constant called ONE_HUNDRED. Checkstyle lets you get around this problem in several ways. The easiest way to deal with particular cases like this is to use the SupressionCommentFilter module. This module lets you deactivate Checkstyle for a section of code:

// CHECKSTYLE:OFF – 100 is not a "magic number" in this case for (int i = 1; i < 100; i++) { // CHECKSTYLE:ON List<Student> students = extractCentile(i, examResults); …. }

Another way to do this is to use the SuppressionFilter, associated with an XML configuration file, where detailed suppressions can be specified. This approach is useful for deactivating rules for large blocks of code or across several classes.

<module name="SuppressionFilter"> <property name="file" value="docs/suppressions.xml"/> </module>

The code above calls a suppressions.xml file, a file that you need to write where you can deactivate particular checks for particular classes, or even for certain lines in a particular class. In the following example, all Javadoc checks are deactivated for the first 50 lines of the Catalog class, and the MagicNumberCheck is deactivated for all unit test classes.

<!DOCTYPE suppressions PUBLIC "-//Puppy Crawl//DTD Suppressions 1.0//EN" "http://www.puppycrawl.com/dtds/suppressions_1_0.dtd"> <suppressions> <suppress checks="Javadoc*" files="Catalog.java" lines="1-50"/> <suppress checks="MagicNumberCheck files="*Test.java"/> </suppressions>

This approach does require extra maintenance work to keep the suppression.xml file up to date. Developers may also be tempted to use wildcards a little excessively, which can reduce the efficiency of CheckStyle audits. In practice, this method should be used sparingly and only after other options have been considered and eliminated.

Thanks for your registration, follow us on our social networks to keep up-to-date