Tutorial: using FindBugs with Maven

FindBugs can be executed using Maven in two different modes: as stand-alone command or as part of the Maven site command.

These two modes require different settings in the project pom.xml but they are not incompatible to each other so we can use both of them.

info48
You can find complete Maven project here.

Stand-alone mode

Let’s start with the stand-alone mode which requires the following configuration in the pom.xml:

<build>
    <plugins>       
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>findbugs-maven-plugin</artifactId>
            <version>3.0.1</version>
        </plugin>
         ... other build plugins ....
    </plugins>
</build>

Please note that the FindBugs plugin definition is inside build – plugins section of the pom file.

Giving the following command:

mvn findbugs:findbugs

FindBugs is run against our project with the following log in the console output:

[INFO] --- findbugs-maven-plugin:3.0.1:findbugs (default-cli) @ CodeQualityGallery ---
[INFO] Fork Value is true
     [java] Warnings generated: 1
[INFO] Done FindBugs Analysis....

warning48
FindBugs analyze the compiled files (*.class). If the project is not compiled or just cleaned, FindBugs will report nothing, without error messages. So take care to build your project before running FindBugs.

A warnings number is reported on the console. Warnings are possible bugs found by the FindBugs detectors.

The warnings details are included in a report created in the file target/findbugsXml.xml which is in XML format and so not really readable.

A better way to examine the warnings is to use the FindBugs native GUI with the command:

mvn findbugs:gui

The FindBugs window shows the bugs on the left, the (read-only) code on the right and the bug explanation below.

FindBugs GUI

You can filter bugs for bug rank from the most critical (“scariest”) to trivial and even, saving project status, comparing project evolution (which means how may bugs has been eliminated/introduced after previous FindBugs check).

warning48All main IDEs (Eclipse, NetBeans, IntelliJ) FindBugs plugins show similar views and they can also let you modify the code so I don’t suggest to use FindBugs native GUI unless you have to create exclusion files (see below) which is easier with the native GUI: select a bug, filter it out and export bug filters.

 

Site mode

Maven site command is used to generate a project “site”, which is a collection of information on the project nicely reported in HTML pages. You can configure which information is included in the site report and, of course, you can add FindBugs analysis results.

Maven site requires a “reporting section” in the pom file.

<reporting>
    <plugins>       
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>findbugs-maven-plugin</artifactId>
            <version>3.0.1</version>
        </plugin>
         ... other site plugins ....
    </plugins>
</reporting>

Giving the following command (note: clean and install options are in to assure that project is compiled and all tests run):

mvn clean install site

on the console output we will see the following:

.....
[INFO] --- maven-site-plugin:3.3:site (default-site) @ CodeQualityGallery ---
[INFO] configuring report plugin org.apache.maven.plugins:maven-jxr-plugin:2.5
[INFO] configuring report plugin org.apache.maven.plugins:maven-project-info-reports-plugin:2.8
[INFO] configuring report plugin org.codehaus.mojo:findbugs-maven-plugin:3.0.1
[INFO] Fork Value is true
     [java] Warnings generated: 2
[INFO] Done FindBugs Analysis....
[INFO] configuring report plugin org.apache.maven.plugins:maven-pmd-plugin:3.4
[WARNING] No project URL defined - decoration links will not be relativized!
[INFO] Rendering site with org.apache.maven.skins:maven-default-skin:jar:1.0 skin.
[INFO] Skipped "Source Xref" report, file "xref/index.html" already exists for the English version.
[INFO] Generating "Source Xref" report    --- maven-jxr-plugin:2.5
[INFO] Generating "Dependency Convergence" report    --- maven-project-info-reports-plugin:2.8
[INFO] Generating "Dependency Information" report    --- maven-project-info-reports-plugin:2.8
[INFO] Generating "About" report    --- maven-project-info-reports-plugin:2.8
[INFO] Generating "Plugin Management" report    --- maven-project-info-reports-plugin:2.8
[INFO] Generating "Project Plugins" report    --- maven-project-info-reports-plugin:2.8
[INFO] Generating "Project Team" report    --- maven-project-info-reports-plugin:2.8
[INFO] Generating "Project Summary" report    --- maven-project-info-reports-plugin:2.8
[INFO] Generating "FindBugs" report    --- findbugs-maven-plugin:3.0.1
[INFO] Generating "PMD" report    --- maven-pmd-plugin:3.4
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
.....

The “site” is created in the target/site dir. Opening the file target/site/index.html with the browser, we will see something like the following:

2015-06-08bIn the Project Reports section you will find the FindBugs report like the following:

2015-06-08c   The report is interesting because it give us the complete picture of our project in the summary section but also the list of the files which have FindBugs detected issues with all details including the priority (i.e. how dangerous could be the problem).

Configuration options

Regardless the used mode, the FindBugs plugin can be configured to modify and tune its behaviour. All below configurations should be placed in the configuration section of the plugin:

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>findbugs-maven-plugin</artifactId>
    <version>3.0.1</version>
    <configuration>
        .....put here
    </configuration>
</plugin>

warning48
Configurations in the build and reporting sections are independent so we can have two different settings in the two modes, stand-alone and site.

Best practice is to use a light and fast configuration on the standalone mode, in order to run quick checks during development and an high effort, production quality configuration for the site mode.

Let’s examine the most important configuration options:

DEBUG: With <debug>true</debug> option, FindBugs will show what is doing during analysis. Useful to fine tune or checks the settings.

EFFORT: with  <effort>Max</effort> we can increase the time FindBugs is allowed to use to analyze the code. More effort means more accurate analysis but, of course, FindBugs run slower.

EXTERNAL PLUGINS: FindBugs can be extended with additional detectors. See my post on the topic. The  <pluginList>plugin1[, plugin2…]</pluginList> configuration option list the plugins to be used. See the sample project for a real example.

EXCLUSIONS: If you need to disable a detector or to disable the analysis on same classes, an exclude list can be specified with the <excludeFilterFile> path_to_exclude_file </excludeFilterFile> option. File syntax is documented here. An easy way to create this file is by using the FindBugs GUI which has an export filter function. See the sample project for a real example.

 

Not null arguments in Java private methods

After the article on not null arguments on public methods, let’s talk about class private methods.

Checking the public method arguments is necessary to guarantee that methods callers are respecting the class API contract.

On the contrary, private methods are not visible to outside code so there is no need the detect contracts violation.

So, can we skip to check nullity of our private methods arguments ?

The answer is no.

Private methods are called by other methods from the same class so we (not class users) are responsible to guarantee that the methods are invoked correctly.

If we pass a null argument to a private method which need a non null argument, this is a bug in our code and we should fix it.

Joshua Bloch, in his famous Effective Java book, suggest to check private methods arguments using assertion.

This is correct approach because assertion are usually enabled during development and test, while we are debugging our code, and disabled in production code.

Let me make small example:

private void metSimple(final String arg) {
    System.out.println(arg.length());
}

The String argument arg of this method cannot be null. Best approach is to check the argument at the begin of the method body:

private void metChecked(final String arg) {
    assert arg != null;
    System.out.println(arg.length());
}

During the devolpment of the class (with assertions enabled) which uses the method, the assert will check nullity of the argument. Assertion error will help us to debug and improve our code.

To have better support from the IDE, we can also use Nonnull annotation (see this article for more details) like as follows:

private void metAnnotatedChecked(@javax.annotation.Nonnull final String arg) {
    assert arg != null;
    System.out.println(arg.length());
}

This is the preferred solution: assert check run at execution time while Nonnull annotation guides the IDE to detect improper method calls.

Using NetBeans 7.3 we have following situation:
NetBeans 7.3

NetBeans detects wrong method calls at lines 14 and 15 thanks to annotations while it does not find problems on lines 12 and 13.

NetBeans is also reporting an “Unnecessary test for null – the expression is never null”) on the assert line.This is a false message because the annotation cannot guarantee that arg method is never null; I have opened a bug report.

Update: this has been fixed on NetBeans 7.4

Using IntelliJ IDEA 12.1 Community Edition we have the following:

IntelliJ

Curiously the two IDEs have the same behavior:

  • same correct warnings (lines 14 and 15)
  • same missed warnings (lines 12 and 13)
  • same “bug” on line 32

Most probably there is some code sharing between the tools.

Eclipse users: please look at the comments on the my article on public methods.

Not null arguments in Java public methods

As Java programmer, one of my references is Joshua Bloch’s Effective Java. In this book, the theme 38 says we should always check the validity of the arguments on each method.

No excuse.

For example, let’s have a very dummy method which prints on the standard output the length of the String passed as argument:

public void metSimple(String arg) {
    System.out.println(arg.length());
}

if we call this method with a null String, we will get a Null Pointer Exception (NPE) at run-time.

Accordingly to Bloch’s book, we should add a proper check to validate the argument like as follow:

public void metChecked(final String arg) {
    if (arg == null) {
        throw new NullPointerException("Argument arg is null");
    }
    System.out.println(arg.length());
}

The check will assure us that the body of the method (here just a simple System.out.println but in real code will be more complex) can work on the argument arg without problems, knowing that the string arg is not null.

Note: we should not use assert instructions to check public methods arguments. Reason is that assert can be disabled. There is also an old but still valid Java article on assertions on this.

The nullity check is done at run-time so we need to work on testing side to have reasonable confidence that null condition (i.e the NPE) will not really happen in front of our customers.

Can we also have some support during coding? I mean, from our fabulous IDE?

Yes, but we need to help them, adding a “not null” annotation on the argument. There are several of these annotations but the standard is @javax.annotation.Nonnull.

Our method becomes:

public void metAnnotatedChecked(@Nonnull final String arg) {
    if (arg == null) {
        throw new NullPointerException("Argument arg is null");
    }
    System.out.println(arg.length());
}

The @Nonnull annotation is from jsr305 library. Maven users can add it in the pom the following dependency:

<dependency>
    <groupId>com.google.code.findbugs</groupId>
    <artifactId>jsr305</artifactId>;
    <version>2.0.1</version>;
</dependency>

The @Nonnull annotation simply says: dear method users, do not try to invoke it with a null as argument.

Important: the @Nonnull annotation is simply an annotation, a kind of hint for the tools. It is not a run-time check and it does not enforce or guarantee that nobody can call the method with a null argument. So our “if arg == null” check should stay there.

The IDEs use these annotations (there are also others like CheckForNull) to perform additional checks (named “null analysis”) during coding. Not at run-time. These checks complements the run-time checks.

Let’s how most popular IDEs use these annotations. To check their behavior I created a calling class as follows: