Contents

Improve code quality through static code analysis

Use SpotBugs to detect bad pratice and bugs into your Java project

Using static analysis tools to detect bugs or bad pratice at early stage in the development process is greatly benefits for the code quality of the project. Moreover, these tools allow to find and correct many errors in a cheaper way before they appear at runtime.

Static analyzers have a knowledge base on various patterns that in certain conditions cause an error and can provide feedbacks to the developper, the existence of which he himself would hardly have guessed.

SpotBugs the successor of FindBugs which is not longer active since few years now is a static analysis tools that checks for more than 400 bug patterns (bug descriptions can be found here). SpotBugs can be easily integrated into your build process since it support Ant, Gradle, Maven.

SpotBugs gradle plugin task


To integrate SpotBugs into your Gradle build script, you only have to add the following snippet into your build.gradle as described on the Gradle plugin website :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
buildscript {
  repositories {
    maven {
      url "https://plugins.gradle.org/m2/"
    }
  }
  dependencies {
    classpath "gradle.plugin.com.github.spotbugs:spotbugs-gradle-plugin:1.6.6"
  }
}

apply plugin: "com.github.spotbugs"

The plugins add 2 tasks to run SpotBugs analysis:

  • spotbugsMain: runs SpotBugs for your production Java source files and also test Java source files since this task depends on the following.
  • spotbugsTest: runs SpotBugs for your test Java source files.

You can also simply use the check task that depends on both previous tasks:

1
./gradlew check

Configure SpotBugs gradle plugin task


The SpotBugs configuration is defined in a similar way that it was did for FindBugs, thus you can use all properties defined for the FindBugs configuration, excepted that you must define them into a spotbugs item rather than into a findbugs.

Configure which report, xml or html will be generated by using the following snippet:

1
2
3
4
5
6
tasks.withType(com.github.spotbugs.SpotBugsTask) {
    reports {
        xml.enabled = false
        html.enabled = true
    }
}

❗ Note that you cannot generate both in the same time.

Generated html report uses the language of your system, if it is not suitable, you can select the report language by setting the property user.language when the SpotBugs analysis is launched. For instance, to generate a report in english, use the command:

1
./gradlew -Duser.language=en check

Others configurations will be define into the spotbugs item as below:

1
2
3
4
5
6
spotbugs {
    ignoreFailures = true
    effort = "max"
    reportLevel = "low"
    includeFilter = file("./spotbugs-include.xml")
}

See meaning of all properties on the FindBugs gradle plugin website.

Sample of SpotBugs report


I used the following Java class that contains several problems as input of the SpotBugs analysis:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class Sample {
    public static void main(String[] args) {
        if (Sample.booleanMethodReturnNull()) {
            System.out.println("True");
        }
        Sample.invalidCast();
        if (Sample.booleanMethodReturnNull()) {
            System.out.println("True");
        }
        double d = Sample.getPI();
        Sample.stringConcat(new String[]{"a","b"});
    }

    private static void invalidCast() {
        final Object doubleValue = Double.valueOf(1.0);
        final Long value = (Long) doubleValue;
        System.out.println("   - " + value);
    }

    private static Boolean booleanMethodReturnNull() {
        return null;
    }

    private static double getPI() {
        return 3.141;
    }

    private static String stringConcat(String array[]) {
        String s = "";
        for (int i = 0; i < array.length; ++i) {
            s = s + array[i];
        }
        return s;
    }

    @Override
    public boolean equals(Object obj) {
        return ((Sample)obj) == this;
    }
}

SpotBugs generates a report with 8 warnings: 2 with high priorities and 6 with medium priorities. It is possible to filter reported warnings by using its priority level and setting the property reportLevel to one of the value low, medium, high.

/post/2018/12/spotbugs/img/SpotBugs-summary.png SpotBugs-warnings.png SpotBugs-details.png

Strategy to enable SpotBugs into a Java project


Enable SpotBugs support at the beginning of the project to report all detected failures is a good idead, nevertheless, adding the support into a existing project with a lot of legacy code can be paintful. Indeed, it could reports a lot of warnings and it can be a nightmare to manage them.

As saw previously, you can use the property reportLevel to report only warnings with a high priority and decrease warnings to take into account. If it is again too much, you can start by working on warnings that the team estimate the most useful and filter the report to only show those. It can be done by setting the property includeFilter with a path to a filter file such as below, for instance, to report only warnings related to method with Boolean return type returning explicit null.

1
2
3
4
5
<FindBugsFilter>
    <Match>
        <Bug pattern="NP_BOOLEAN_RETURN_NULL" />
    </Match>
</FindBugsFilter>

To have more information on how to write filter file, see the official documentation.

Rather than enable bug patterns one-by-one, the counterside approach can be choose to disable all bug patterns that are considered less valuable by the team. In this case, use the property excludeFilter.

Publish SpotBugs report into Jenkins


SpotBugs can be easily integrated into Jenkins, one of the leading open-source automation servers. Use it through docker with the following command line:

1
docker run --name jenkins -d -v jenkins_home:/var/jenkins_home -p 8080:8080 -p 50000:50000 jenkins/jenkins:lts

Now install the Warnings plugin by going to Manage Jenkins/Manage Plugins, into available plugins select Warnings Next Generation and install it without restart.

In order to add SpotBugs analysis into your build job, go to the project and select Configure, into the Build section, add a build step that will invoke gradle script and set the tasks to check. To finish, into the Post-build Actions, add a step to Record compiler warnings and static analysis results to publish SpotBugs results and set the Report File Pattern to **/build/reports/spotbugs/main.xml which represent the path where the SpotBugs report is generated.

❗ Do not forget to configure the tool to generate the XML report as describe previously.

/post/2018/12/spotbugs/img/SpotBugs-warning-jenkins.png /post/2018/12/spotbugs/img/SpotBugs-trend-jenkins.png