Setting Up Static Code Analysis for Java
Need help setting up static code analysis for your Java project? Check out this tutorial on how to set up the static code analysis.
Join the DZone community and get the full member experience.
Join For FreeIntroduction
In this article, we will go through the basic setup of static code analysis for your Java project.
Why is static code analysis important? It helps us to ensure the overall code quality, fix bugs in the early stage of development, and ensure that each developer is using the same coding standards when writing the code.
There are three basic tools that we are going to use for our static code analysis: CheckStyle, Findbugs, PMD.
CheckStyle
CheckStyle is a tool that helps programmers write code that aligns with already agreed upon coding standards. It automatically checks if the code adheres to the coding standards used on a project.
FindBugs
Fine people of the University of Maryland built this fantastic tool for us. What it basically does for us is, of course, find bugs in our code. FindBugs analyses our code and generates a report, giving us a list of all the bugs that could cause a program to misbehave. One of the good examples of the bugs that could be detected are infinite loops, unused variables, security, threading issues, and many more.
PMD
PMD is another useful tool in our static code analyzers toolbox. Beside reporting many coding issues (e.g. possible memory leaks), PMD can check if our code was commented properly if our variables are named properly and our method contains more than the specified number of lines. PMD is highly configurable and the latest releases play quite well with Lombok annotations. Previously, we needed to define custom excluded rules in order for PMD to play nice with Lombok.
Copy/Paste Detector (CPD) is an integrated part of PMD and is used to detect duplicated code in a source code.
Setting Up Static Code Analysis
We are going to use Gradle as our build tool. Gradle already has a set of plugins that we are going to use for our static code analysis.
Static analysis setup files will reside in ./gradle/static-code-analysis
folder. Each of our static analysis tools will have its own dedicated folder where we will hold additional configuration files for each of the tools. Finally, we’ll use staticCodeAnalysis.gradle
to aggregate all our static code analysis settings. It will contain all the configuration settings needed to run static code analysis for our project.
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'de.aaschmid:gradle-cpd-plugin:1.1'
}
}
apply plugin: 'checkstyle'
apply plugin: 'findbugs'
apply plugin: 'pmd'
apply plugin: de.aaschmid.gradle.plugins.cpd.CpdPlugin
Ok, let’s jump into setting the static code analysis.
Once the plugins are included in the build script, we can start configuring each of the plugins. First, we are going to configure the CheckStyle plugin.
Setting CheckStyle
For CheckStyle, we are going to set the ignoreFailures
flag, toolVersion
, and configFile
, which will point to the location of a configuration file. As a base for our configuration file, we are going to use Google Code Style settings. The configurations are basically the same — the only difference is that we are going to use four space instead of two space indentation. And, that’s it. Nothing more needs to be done for CheckStyle. Let’s set up the FindBugs next:
checkstyle {
toolVersion = '8.12'
ignoreFailures = false
configFile = file("${rootGradleDir}/static-code-analysis/checkstyle/checkstyle.xml")
}
We are explicitly setting the plugin not to ignore failures i.e. ignoreFailures
flag is set to false
. What that basically means is that our project build will fail if we run into any issue during our static code analysis check. If you think about it, this has a lot of sense. Our CI/CD pipeline should fail in case we run upon any issue in our code base. Being it compile failure, unit test failure, code analysis, as long as we have an issue, we shouldn’t be able to continue with our pipeline.
Setting FindBugs
In most cases, we should specify only toolVersion
and ignoreFailures
. There are other options we could set here, such as specifying which bug detectors are going to be run or to include/exclude lists of files that are going to be checked in our code base. For our example, we will leave the default values here: all default bug detectors will be run, and we are not going to exclude any file from FindBugs detection.
findbugs {
toolVersion = '3.0.1'
ignoreFailures = false
}
Setting PMD
For PMD, besides toolVersion
and ignoreFailures
, we are going to set the rule sets for our code analysis. We have can set the rule sets in two ways. We can specify them directly inside the PMD plugin configuration using ruleSets
array, or we could extract the rule sets to separate the XML file and reference the file using the ruleSetFiles
configuration parameter. We are going to choose the latter option since it is more descriptive and allows us to provide exclusions to default rule sets categories. For the codestyle category, we are excluding DefaultPackage
and OnlyOneReturn
rules. You can check out ruleset.xml for full setup.
pmd {
toolVersion = '6.7.0'
ignoreFailures = false
ruleSetFiles = files("${rootGradleDir}/static-code-analysis/pmd/ruleset.xml")
ruleSets = []
rulePriority = 3
}
Setting CPD
For Copy/Paste bug detection, we need to configure the CPD plugin. First, let’s set the minimumTokenCount
to 100
. This means that the plugin will detect a duplicate code bug if it finds around 5– 10 lines of the same code in separate places. If only four lines of code are matched, the bug will not be detected. One useful option — especially if you are using frameworks — is to set the ignoreAnnotations
to true
. It will allow us to ignore “false positives” and ignore cases where classes or methods have the same 5– 6 lines of annotations. Finally, we’ll enable and generate XML by setting xml.enabled
to true
.
cpd {
language = 'java'
toolVersion = '6.0.0'
minimumTokenCount = 100 // approximately 5-10 lines
}
cpdCheck {
reports {
text.enabled = false
xml.enabled = true
}
ignoreAnnotations = true
source = sourceSets.main.allJava
}
view raw
For remaining static analysis report plugins, we will enable generation of the HTML report instead of XML one.
tasks.withType(Checkstyle) {
reports {
xml.enabled false
html.enabled true
}
}
tasks.withType(FindBugs) {
reports {
xml.enabled false
html.enabled true
}
}
tasks.withType(Pmd) {
reports {
xml.enabled false
html.enabled true
}
}
Great! We are done with the static analysis code configuration. Now, we just need to include staticCodeAnalysis.gradle
into our Gradle build script:
apply from: "${rootGradleDir}/staticCodeAnalysis.gradle"
Running Static Code Analysis
Static code analysis plugins will run with the same Java version used to run Gradle.
Each plugin will add its own dependencies to the Java plugin check
task (e.g. pmdMain, cpdMain). Whenever we run ./gradlew clean build
, the internally check
task will be triggered and static analysis steps will be run for our project. If any of the code analysis steps fail, our build will fail as well. Static code analysis reports will be generated under ./build/reports
.
If in some situations we need to “loose” the specified static code rules, we can always suppress static analysis errors by using @SuppressWarnings
annotation. In order to suppress the warning for having too many methods in a class, we could put @SuppressWargning("PMD.TooManyMethods")
on the given class.
We advise keeping static analysis “on” for the test classes as well. We should always treat tests as an integrated part of our project. Test code should conform to the same styles/rules we use throughout our project.
Summary
In this post, we went through a short explanation on how to set up the static code analysis for a Java project. Hope you got a good overview on how you can use it in your project, how it can help you to improve overall code quality, and detect bugs in the early stage of project development.
The sample code is available on GitHub. Enjoy static code analyzing!
Published at DZone with permission of Mladen Bolic. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments