Automatic code analysis with Checkstyle
Introduction
Maintaining code quality is a key element of effective and efficient software development.
In this context, code quality control tools play an important role, and one of the most popular is Checkstyle.
In this article, I will show how to easily implement this tool into our daily work using an example of an application configured in Gradle.
1. Initialization of the Gradle project
mkdir ~/j-labs-blog-checkstyle
cd ~/j-labs-blog-checkstyle
gradle init --type java-application --dsl groovy --test-framework testng --project-name j‑labs-blog-checkstyle --package jlabsblog.jwt 2. Checkstyle configuration
Checkstyle configuration is divided into two components, which will be described in the following subsections:
- Enabling the plugin (and possible additional configuration) in the Gradle configuration file,
- Configuration in XML containing a list of rules under which the code will be tested.
2.1 Gradle configuration
To enable Checkstyle, add the checkstyle plugin into the build.gradle configuration:
plugins {
// ...
id 'checkstyle'
}2.2 Contents of checkstyle.xml
The syntax of the checkstyle file consists of 2 elements:
- Document Type Definition (DOCTYPE)
- List of rules (
moduletags).
<!DOCTYPE module PUBLIC
"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
"https://checkstyle.org/dtds/configuration_1_3.dtd">
<module name="Checker">
<module name="TreeWalker">
...
<module name="MethodName">
<property name="format" value="^[a-z]([a-zA-Z0-9]+)*$"/>
</module>
<module name="MethodLength">
<property name="max" value="4"/>
</module>
...
</module>
</module>Below I will present some sample rules with an example of use.
Annotations
This is a category of rules used to validate annotations. An example from this category is the AnnotationLocation rule, which will check if there is more than one annotation on the same line:
// <module name="Checker">
// <module name="TreeWalker">
// <module name="AnnotationLocation"/>
@SomeAnnotation @OtherAnnotation // violation
public void foo() {
}
@SomeAnnotation
@OtherAnnotation
public void bar() {
}Code blocks
This is a category of rules used to validate blocks of code. An example from this category is the AvoidNestedBlocks rule, which will check if a nested block is present:
// <module name="Checker">
// <module name="TreeWalker">
// <module name="AvoidNestedBlocks"/>
public void foo() {
{ // violation
System.out.println();
}
}
public void bar() {
System.out.println();
}Class design
This is a category of rules used to validate a class design. An example from this category is the OneTopLevelClass rule, which will check if there is more than one definition of an unnested class in the file:
// <module name="Checker">
// <module name="TreeWalker">
// <module name="OneTopLevelClass">
// --- Foo.java ---
public class Foo {}
class Bar {} // violationCoding
This is a category of rules used to validate the code being written. An example from this category is the ReturnCount rule, which will check that a method implementation does not exceed the allowed number of return declarations (the default is 2 for type returners and 1 for void):
// <module name="Checker">
// <module name="TreeWalker">
// <module name="ReturnCount">
// <property name="max" value="2"/>
public String foo(int i) { // violation - Return count is 3
switch (i) {
case 200: return "ok";
case 400: return "client_error";
}
return "unknown";
}
public String bar(int i) {
return switch (i) {
case 200 -> "ok";
case 400 -> "client_error";
default -> "unknown";
};
}Headers
This is a category of rules used to validate file headers. An example from this category is the Header rule, which will check if the appropriate header is present.
// <module name="Checker">
// <module name="Header">
// <property name="header" value="// Copyright (C) J-Labs\n// All rights reserved"/>
// --- Foo.java ---
public class Foo {} // violation
// --- Bar.java ---
// Copyright (C) J-Labs
// All rights reserved
public class Bar {}Imports
This is a category of rules used to validate imports. An example from this category is the IllegalImport rule, which will check for inappropriate imports.
// <module name="Checker">
// <module name="TreeWalker">
// <module name="IllegalImport"/>
// <property name="illegalPkgs" value="forbiddenmodule"/>
// --- Foo.java ---
import forbiddenmodule.ForbiddenClass; // violation
public class Foo {} // violationJavaDoc comments
This is a category of rules applied to JavaDoc. An example from this category is the JavadocMethod rule, which will validate existing documentation. In the following example, one error will be reported due to a missing description of the i parameter:
// <module name="Checker">
// <module name="TreeWalker">
// <module name="JavadocMethod"/>
/**
*
*/
public void foo(int i) {} // violation
public void bar(int i) {}
/**
*
* @param i
*/
public void baz(int i) {}Naming conventions
This is a category of rules used for naming validation. An example from this category is the LocalVariableName rule, which will validate local variable names:
// <module name="Checker">
// <module name="TreeWalker">
// <module name="LocalVariableName"/>
public void foo(int i) {
int VAR = 0; // violation
int variable = 0;
}The list of possible rules to be applied is available directly on the plugin page Checkstyle
2.3 Content of supressions.xml
If the specifics of our project require the omission of particular classes we can configure this with the supressions.xml file, which, like checkstyle, relies on 2 elements:
- Document Type Definition (DOCTYPE)
- List of rules (Tags
supressions)
<!DOCTYPE suppressions PUBLIC
"-//Checkstyle//DTD Suppressions 1.1//EN"
"https://checkstyle.org/dtds/suppressions_1_1.dtd">
<suppressions>
<suppress files="DatabaseMigrationScript.java" checks="MethodName"/>
</suppressions>The supressions.xml file must be included in checkstyle.xml for the changes to work:
<module name="Checker">
...
<module name="SuppressionFilter">
<property name="file" value="${config_loc}/suppressions.xml"/>
</module>
</module>2.4 XML configuration location
By default, the checkstyle.xml configuration should be located in the root folder of the project:
<root>
- config
-- checkstyle
--- checkstyle.xml
--- suppressions.xml2.5 Overriding the default configuration in Gradle
checkstyleMain
If you want to overwrite the expected XML configuration place you need to indicate it in the build.gradle configuration:
checkstyleMain {
configFile = file("${rootDir}/app/src/main/resources/config/checkstyle/checkstyle.xml")
configDirectory = file("${rootDir}/app/src/main/resources/config/checkstyle")
}This approach also allows us to separate the configuration between modules. To do this, simply add the above settings in the build.gradle files of each module, and then add the configuration XMLs in the appropriate places, for example:
<root>
- app
-- config
--- checkstyle
---- checkstyle.xml
---- suppressions.xml
- app2
-- config
--- checkstyle
---- checkstyle.xml
---- suppressions.xml
...checkstyleTest
To set up a separate configuration for tests, point to the configuration file in build.gradle :
checkstyleTest {
configFile = file("${rootDir}/config/checkstyle/checkstyle-test.xml")
configDirectory = file("${rootDir}/app/src/main/resources/config/checkstyle")
}3. Report
To run Checkstyle you need to build a project:
gradle build
or
gradle checkstyleMain checkstyleTestIf there are errors in the code, the console will return an error, and the logs will contain an appropriate message, for example:
> Task :app:checkstyleMain
[ant:checkstyle] [ERROR] \j-labs-blog-checkstyle\app\src\main\java\jlabsblog\App.java:8:17: Name 'Bad_Method_Name' must match pattern '^[a-z]([a-zA-Z0-9]+)*$'. [MethodName]
> Task :app:checkstyleMain FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':app:checkstyleMain'.
> A failure occurred while executing org.gradle.api.plugins.quality.internal.CheckstyleAction
> Checkstyle rule violations were found. See the report at: file:///j-labs-blog-checkstyle/app/build/reports/checkstyle/main.html
Checkstyle files with violations: 1
Checkstyle violations by severity: [error:1]The returned result in the console will also show a link to the report in HTML form:
4. IDE configuration
The greatest benefit of using the Checkstyle plugin can be achieved by integrating it with a development environment.
The available integrations can be seen at Checkstyle website.
In the following subsections, an example of integration with Intellij IDEA will be presented based on the Checkstyle-IDEA plugin, which allows code analysis and error highlighting in real time.
4.1 Plugin installation
Open the IDE settings and go to install the plugin:
File -> Settings (Ctrl+Alt+S) -> Plugins -> Checkstyle-IDEA
4.2 Plugin configuration
After restarting the application, open the IDE settings again and go to the plugin configuration:
File -> Settings (Ctrl+Alt+S) -> Tools -> Checkstyle -> Configuration File -> +.
Then indicate the location of the XML configuration file:


From now on, the plugin will notify us about errors in real time:
4.3 Include multiple XML configurations
If there are multiple modules in our project that have separate XML configurations, you need to repeat the previous point for each of them.
Since the Checkstyle-IDEA plugin does not take into account the build.gradle configuration, the configuration from checkstyleMain will not be applied.
Therefore, you need to use a workaround that will cause the checkstyle.xml configuration to be used only within the specified module / package.
In the example below, this will be the jlabsblog main package in the app module:
<module name="Checker">
<module name="BeforeExecutionExclusionFileFilter">
<property name="fileNamePattern" value="^(?!.*([\\/]app[\\/]src[\\/]main[\\/]java[\\/]jlabsblog[\\/].*\.java)).*$"/>
...
</module>
</module>This is the equivalent of the configuration in checkstyleMain :
checkstyleMain {
source = [
'../app/src/main/java/jlabsblog'
]
configFile = file("${rootDir}/app/src/main/resources/config/checkstyle/checkstyle-test.xml")
configDirectory = file("${rootDir}/app/src/main/resources/config/checkstyle")
}Summary
Checkstyle is a valuable tool supporting the maintenance of high code quality in software projects.
Automatic code analysis ensures compliance with accepted standards, eliminates errors, and facilitates daily work by supporting the code-review process.
The article above shows how to enable the plugin in a Gradle project. Using a concrete example, it was shown how to configure the tool for multi-module applications.
After reading this article, you should be able to configure Checkstyle in your project so that it catches errors and any violations of conventions adopted in your team in real time.
Bibliography
- https://docs.gradle.org/current/userguide/checkstyle_plugin.html
- https://checkstyle.org/checks.html
- https://github.com/checkstyle/checkstyle/issues/991
- https://github.com/checkstyle/checkstyle/blob/master/config/checkstyle-checks.xml
Meet the geek-tastic people, and allow us to amaze you with what it's like to work with j‑labs!
Contact us


