For more information on SpotBugs, see the SpotBugs home page.
We routinely run SpotBugs as part of our continuous integration process. You can see the detailed results of the most recent (daily) run along with recent progress trend online.
If SpotBugs is finding a false positive, a bug that's not really a bug, you can turn it off with an annotation such as:
import edu.umd.cs.findbugs.annotations; @SuppressFBWarnings("FE_FLOATING_POINT_EQUALITY", "Even tiny differences should trigger update")Although Java itself considers it optional, we require the second "justification" argument. Explaining why you've added this annotation to suppress a message will help whoever comes after you and is trying to understand the code. It will also help make sure you properly understand the cause of the underlying bug report: Sometimes what seems a false positive really isn't. Annotations without a justification clause will periodically be removed. Note that the @SuppressFBWarnings contents in this form should be all on one line so that automated scanners can more reliably see it.
For clarity, this annotation also supports a form that lets you be more verbose:
@edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "FE_FLOATING_POINT_EQUALITY", justification = "OK to compare floats, as even tiny differences should trigger update")This can make it easier to see what is what when quickly scanning through the code.
If you need to put more than one message type in an annotation, use array syntax:
@edu.umd.cs.findbugs.annotations.SuppressFBWarnings("{type1},{type2}","why both are needed")
There are also Java and SpotBugs annotations that can help it better understand your code. Sometimes they'll give it enough understanding of e.g. when a variable can be null, that it'll no longer make false-positive mistakes. For more on this, see the Java annotations and SpotBugs annotation pages.
The basics of annotations are covered in a Java annotations tutorial.
It can be useful to mark code with one of the following annotations so that SpotBugs does a good job of reasoning about it:
javax.annotation.Nonnull
- The annotated element must not be null.
Annotated fields must not be null after construction has completed. Annotated methods
must have non-null return values. Use
javax.annotation.ParametersAreNonnullByDefault on the class declaration (the start of
the class) to set @Nonnull for an entire class. Note that SpotBugs won't let you compare
a @Nonnull value to null; that's an error that SpotBugs wants to find via static
analysis. If you are annotating a part of the external API, and you want to double-check at
runtime, use java.util.Objects.requireNonNull(..),
for example:
public Car(@Nonnull Engine engine, @Nonnull Transmission transmission) { this.engine = java.util.Objects.requireNonNull(engine, "Engine cannot be null"); this.transmission = java.util.Objects.requireNonNull(transmission, "Transmission cannot be null"); }
javax.annotation.CheckForNull
- the annotated variable, parameter or
return value may have a null value, so all uses should appropriately handle that. Please
put this on method definitions to say that the return value should be checked for null.
javax.annotation.OverridingMethodsMustInvokeSuper
- Used to annotate a
method that, if overridden, must (or should) invoke super in the overriding method.
Examples of such methods include finalize()
and clone()
.
Note this replaces the deprecated edu.umd.cs.findbugs.annotations.OverrideMustInvoke
.
javax.annotation.CheckReturnValue
- annotates a method to say the method
has no side effects, so there is no point in calling it without checking its return value.
net.jcip.annotations.Immutable
- An object of this class can't be changed after it was created. This allows both better
checking of logic, and also simplifies use by your colleagues, so it's good to create
classes that have this property and then annotate them.
net.jcip.annotations.NotThreadSafe
- a class that isn't thread-safe, so shouldn't be checked for concurrency issues. Often
used for Swing-based classes, but note that some Swing components (e.g. monitor windows,
classes with listeners) do have to accept input from other threads.
net.jcip.annotations.ThreadSafe
- classes that do have to be usable for multiple threads. SpotBugs generally assumes
this, but it's good to put it on a class that's intended to be thread-safe as a reminder
to future developers.
net.jcip.annotations.GuardedBy
- "The field or method to which this annotation is applied can only be accessed when
holding a particular lock, which may be a built-in (synchronization) lock, or may be an
explicit java.util.concurrent.Lock."
Your code should ensure that the synchronization is done around references to the annotated field or method. SpotBugs will (sometimes) check that.
We do not use these annotations:
javax.annotation.Nullable
- This doesn't really mean what people think it does, as SpotBugs doesn't really check
anything when this is used. From the SpotBugs documentation:
SpotBugs will treat the annotated items as though they had no annotation. In practice
this annotation is useful only for overriding an overarching NonNull annotation. Use
javax.annotation.ParametersAreNullableByDefault to set it for an entire class. Prefer
the use of CheckForNull
.
To run it locally:
spotbugs.home = /Users/jake/.spotbugs/spotbugs-4.2.3
ant spotbugsor for the test code
ant tests-spotbugswhich will create a
spotbugs.html
or tests-spotbugs.html
file in the JMRI base directory that you can open in a browser.
ant spotbugs-ci
target is similar, except it creates the output as a
spotbugs.xml
XML file that Jenkins uses to track which items have been fixed,
etc.
The .spotbugs.xml
file specifies which items in SpotBugs reports are suppressed for the JMRI project's usual
reporting via Jenkins. The .spotbugs-check.xml file
is a super-set which identifies which are significant enough to fail CI. (This is specified
two places in the pom.xml
, which is used by the scripts/travis.sh
to control Maven running, which in turn is used by the .travis.yml
file as the
Travis run-time script)
Simon White added FindBugs support to our Ant-based build chain during the development of JMRI 2.5.5.
We've been making slow but continuous progress on removing these, although new Bug patterns are constantly being added to Spotbugs:
Category | JMRI 2.5.4 | JMRI 4.13.3 | JMRI 4.17.3 | JMRI 5.5.3 |
---|---|---|---|---|
Bad practice Warnings | 164 | 13 | 0 | 0 |
Correctness Warnings | 77 | 25 | 25 | |
Experimental Warnings | 7 | |||
Malicious code vulnerability Warnings | 221 | (disabled) | ||
Multithreaded correctness Warnings | 90 | 175 | 165 | 198 |
Performance Warnings | 459 | 15 | 1 | 0 |
Style / Dodgy Code Warnings | 304 | 406 | 127 | 295 |
Total | 1322 | 636 | 293 | 518 |
Medium Priority | 199 | 79 | 427 | |
Low Priority | 437 | 214 | 128 | |
@SuppressFBWarnings Lines |
868 | 873 |
JMRI 5.1.1 SB 4.7.0 |
JMRI 5.5.3 SB 4.7.3 |
|
---|---|---|
High Priority Total | 251 | 4 |
Medium Priority Total | 4692 | 328 |
Low Priority Total | 988 | 371 |
Total Warnings | 5931 | 703 |
High Priority Density | 0.95 | 0.01 |
Medium Priority Density | 17.77 | 1.19 |
Low Priority Density | 3.74 | 1.35 |
Total Density | 22.46 | 2.55 |
Density - Defects per Thousand lines of non-commenting source statements.
A lot of work has gone into JMRI cycle to bring the bug count down. The Continuous Integration server runs SpotBugs twice a day, which helps developers see the results of their coding without having to set up to run SpotBugs themselves.
If you are checking code in to the JMRI repository, please check the CI server and make sure that your changes do not introduce new errors.