FindBugs Java Code Debugging Tool

Sang Shin, sang.shin@sun.com, Sun Microsystems, www.javapassion.com/javaprogrammingadv


FindBugs is a Java application which uses static analysis to look for bugs in Java code.  Static analysis tools promise to find existing bugs in your code without requiring much effort on the part of the developer.

In this lab, you are going exercise basic features of the FindBugs.

Expected duration: 90 minutes (not including time for homework)


Software Needed

Before you begin, you need to install the following software on your computer.


Change Log



Lab Exercises


Exercise 1: Run FindBugs in Text UI mode

In this exercise, you are going to run FindBugs in Text UI mode.


(1.1) Display FindBugs help


1.  Go to the directory where you unzipped the hands-on lab zip file.  The hands-on lab zip file contains the FindBugs under findbugs-1.3.1 directory.
2.  Type findbugs -textui.  You  are running FindBugs in Text UI mode.

C:\handsonlabs\javadebugfindbugs\findbugs-1.3.1\bin>findbugs -textui
Usage: findbugs [general options] -textui [command line options...] [jar/zip/class files, directories...]
General options:
  -gui             Use the Graphical UI (default behavior)
  -gui1            Use the older Graphical UI
  -textui          Use the Text UI
  -jvmArgs args    Pass args to JVM
  -maxHeap size    Maximum Java heap size in megabytes (default=384)
  -javahome <dir>  Specify location of JRE
  -help            Display command line options
  -debug           Enable debug tracing in FindBugs
Command line options:
  -project <project>                       analyze given project
  -home <home directory>                   specify FindBugs home directory
  -pluginList <jar1[;jar2...]>             specify list of plugin Jar files to load
  -effort[:min|default|max]                set analysis effort level
  -adjustExperimental                      lower priority of experimental Bug Patterns
  -workHard                                ensure analysis effort is at least 'default'
  -conserveSpace                           same as -effort:min (for backward compatibility)
  -showPlugins                             show list of available plugins
  -timestampNow                            set timestamp of results to be current time
  -quiet                                   suppress error messages
  -longBugCodes                            report long bug codes
  -release <release name>                  set the release name of the analyzed application
  -experimental                            report all warnings including experimental bug patterns
  -low                                     report all warnings
  -medium                                  report only medium and high priority warnings [default]
  -high                                    report only high priority warnings
  -sortByClass                             sort warnings by class
  -xml[:withMessages]                      XML output (optionally with messages)
  -xdocs                                   xdoc XML output to use with Apache Maven
  -html[:stylesheet]                       Generate HTML output (default stylesheet is default.xsl)
  -emacs                                   Use emacs reporting format
  -relaxed                                 Relaxed reporting mode (more false positives!)
  -train[:outputDir]                       Save training data (experimental); output dir defaults to '.'
  -useTraining[:inputDir]                  Use training data (experimental); input dir defaults to '.'
  -sourceInfo <filename>                   Specify source info file (line numbers for fields/classes)
  -projectName <project name>              Descriptive name of project
  -output <filename>                       Save output in named file
  -visitors <v1[,v2...]>                   run only named visitors
  -omitVisitors <v1[,v2...]>               omit named visitors
  -chooseVisitors <+v1,-v2,...>            selectively enable/disable detectors
  -choosePlugins <+p1,-p2,...>             selectively enable/disable plugins
  -adjustPriority <v1=(raise|lower)[,...]> raise/lower priority of warnings for given visitor(s)
  -bugCategories <cat1[,cat2...]>          only report bugs in given categories
  -onlyAnalyze <classes/packages>          only analyze given classes and packages
  -excludeBugs <baseline bugs>             exclude bugs that are also reported in the baseline xml output
  -exclude <filter file>                   exclude bugs matching given filter
  -include <filter file>                   include only bugs matching given filter
  -nested[:true|false]                     analyze nested jar/zip archives (default=true)
  -auxclasspath <classpath>                set aux classpath for analysis
  -sourcepath <source path>                set source path for analyzed classes
  -exitcode                                set exit code of process
  -xargs                                   get list of classfiles/jarfiles from standard input rather than command line

3. Run FindBugs over junit-4.4.jar file.

C:\handsonlabs\javadebugfindbugs\findbugs-1.3.1\bin>findbugs -textui ..\..\samplecodes\junit\junit-4.4.jar

M B NP: org.junit.experimental.theories.internal.ParameterizedAssertionError.equals(Object) does not check for null argument Dereferenced at ParameterizedAssertionError.java:[line 21]
H B HE: org.junit.experimental.theories.internal.ParameterizedAssertionError defines equals and uses Object.hashCode()  At ParameterizedAssertionError.java:[line 21]
M B Se: Class org.junit.Assume$AssumptionViolatedException defines non-transient non-serializable instance field fMatcher  In Assume.java
M B It: org.hamcrest.internal.ArrayIterator.next() can't throw NoSuchElement exception  At ArrayIterator.java:[line 22]
M P Bx: Method junit.framework.Assert.assertEquals(String, long, long) invokes inefficient new Long(long) constructor; use Long.valueOf(long) instead  At Assert.java:[line 130]
M P Bx: Method junit.framework.Assert.assertEquals(String, byte, byte) invokes inefficient new Byte(byte) constructor; use Byte.valueOf(byte) instead  At Assert.java:[line 156]
M P Bx: Method junit.framework.Assert.assertEquals(String, char, char) invokes inefficient new Character(char) constructor; use Character.valueOf(char) instead  At Assert.java:[line 169]
M P Bx: Method junit.framework.Assert.assertEquals(String, short, short) invokes inefficient new Short(short) constructor; use Short.valueOf(short) instead  At Assert.java:[line 182]
M P Bx: Method junit.framework.Assert.assertEquals(String, int, int) invokes inefficient new Integer(int) constructor; use Integer.valueOf(int) instead  At Assert.java:[line 195]
M D ST: Write to static field junit.runner.BaseTestRunner.fgFilterStack from instance method junit.runner.BaseTestRunner.processArguments(String[])  At BaseTestRunner.java:[line 160]
M B OS: junit.runner.BaseTestRunner.readPreferences() may fail to close stream  At BaseTestRunner.java:[line 229]
H M LI: Incorrect lazy initialization and update of static field junit.runner.BaseTestRunner.fPreferences in junit.runner.BaseTestRunner.getPreferences()  At BaseTestRunner.java:[lines 48-49]
M V EI2: new org.junit.internal.requests.ClassesRequest(String, Class[]) may expose internal representation by storing an externally mutable object into ClassesRequest.fClasses  At ClassesRequest.java:[line 12]
M B Dm: junit.textui.TestRunner.runFailed(String) invokes System.exit(...), which shuts down the entire virtual machine  At TestRunner.java:[line 195]
Warnings generated: 14

C:\handsonlabs\javadebugfindbugs\findbugs-1.3.1\bin>findbugs -textui -longBugCodes ..\..\samplecodes\junit\junit-4.4.jar
M B NP_EQUALS_SHOULD_HANDLE_NULL_ARGUMENT NP: org.junit.experimental.theories.internal.ParameterizedAssertionError.equals(Object) does not check for null argument  Dereferenced at ParameterizedAssertionError.java:[line 21]
H B HE_EQUALS_USE_HASHCODE HE: org.junit.experimental.theories.internal.ParameterizedAssertionError defines equals and uses Object.hashCode()  At ParameterizedAssertionError.java:[line 21]
M B SE_BAD_FIELD Se: Class org.junit.Assume$AssumptionViolatedException defines non-transient non-serializable instance field fMatcher  In A
ssume.java
M B IT_NO_SUCH_ELEMENT It: org.hamcrest.internal.ArrayIterator.next() can't throw NoSuchElement exception  At ArrayIterator.java:[line 22]
M P DM_NUMBER_CTOR Bx: Method junit.framework.Assert.assertEquals(String, long, long) invokes inefficient new Long(long) constructor; use Long.valueOf(long) instead  At Assert.java:[line 130]
M P DM_NUMBER_CTOR Bx: Method junit.framework.Assert.assertEquals(String, byte, byte) invokes inefficient new Byte(byte) constructor; use Byte.valueOf(byte) instead  At Assert.java:[line 156]
M P DM_NUMBER_CTOR Bx: Method junit.framework.Assert.assertEquals(String, char, char) invokes inefficient new Character(char) constructor; use Character.valueOf(char) instead  At Assert.java:[line 169]
M P DM_NUMBER_CTOR Bx: Method junit.framework.Assert.assertEquals(String, short, short) invokes inefficient new Short(short) constructor; use Short.valueOf(short) instead  At Assert.java:[line 182]
M P DM_NUMBER_CTOR Bx: Method junit.framework.Assert.assertEquals(String, int, int) invokes inefficient new Integer(int) constructor; use Integer.valueOf(int) instead  At Assert.java:[line 195]
M D ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD ST: Write to static field junit.runner.BaseTestRunner.fgFilterStack from instance method junit.runner.BaseTestRunner.processArguments(String[])  AtBaseTestRunner.java:[line 160]
M B OS_OPEN_STREAM OS: junit.runner.BaseTestRunner.readPreferences() may fail to close stream  At BaseTestRunner.java:[line 229]
H M LI_LAZY_INIT_UPDATE_STATIC LI: Incorrect lazy initialization and update of static field junit.runner.BaseTestRunner.fPreferences in junit.runner.BaseTestRunner.getPreferences()  At BaseTestRunner.java:[line 48-49]
M V EI_EXPOSE_REP2 EI2: new org.junit.internal.requests.ClassesRequest(String, Class[]) may expose internal representation by storing an externally mutable object into ClassesRequest.fClasses  At ClassesRequest.java:[line 12]
M B DM_EXIT Dm: junit.textui.TestRunner.runFailed(String) invokes System.exit(...), which shuts down the entire virtual machine  At TestRunner.java:[line 195]
Warnings generated: 14


4.  Take a look at the source code where one of the bugs (line that is highlighted in bold font above) is located.

/**
 *
 */
package org.junit.experimental.theories.internal;

import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;


public class ParameterizedAssertionError extends RuntimeException {
    private static final long serialVersionUID = 1L;

    public ParameterizedAssertionError(Throwable targetException,
            String methodName, Object... params) {
        super(String.format("%s(%s)", methodName, join(", ", params)),
                targetException);
    }

    @Override public boolean equals(Object obj) {
        return toString().equals(obj.toString());
    }

    public static String join(String delimiter, Object... params) {
        return join(delimiter, Arrays.asList(params));
    }

    public static String join(String delimiter,
            Collection<Object> values) {
        StringBuffer buffer = new StringBuffer();
        Iterator<Object> iter = values.iterator();
        while (iter.hasNext()) {
            Object next = iter.next();
            buffer.append(String.valueOf(next));
            if (iter.hasNext()) {
                buffer.append(delimiter);
            }
        }
        return buffer.toString();
    }
}
ParameterizedAssertionError.java

                                                                                                              return to top of the exercise

Summary

In this exercise, you learned how to run FindBugs at the Text UI mode.

                                                                                                                        return to the top


Exercise 2: Run FindBugs in GUI mode

In this exercise, you are going to run FindBugs in GUI mode.


(2.1) Run FindBugs in GUI mode


1. Start FindBugs in GUI mode

C:\handsonlabs\javadebugfindbugs\findbugs-1.3.1\bin>findbugs -gui

2. Create a new FindBugs project


Figure-2.11: FindBugs GUI

3. Add JUnit jar file.

Figure-2.12: New Project

Figure-2.13: Open target

Figure-2.14: Close New Project window

Figure-2.15: Result

                                                                                                              return to top of the exercise

(2.2) Add source codes


1. Select File->Reconfigure.


Figure-2.16: Reconfigure to add sources

2. Click Add button of the Source directories section.


Figure-2.17: Add sources

3. Selec src under <LAB_UNZIPPED_DIRECTORY>/javadebugfindbugs/samplecodes/junit directory. Click Open.


Figure-2.18: Select root source directory

4. Click FInish.


Figure-2.19: Close Reconfigure window

5. Click Yes.


Figure-2.20: Redo analysis confirmation

6.  Expand Bugs->Bad practice->Dubious method used->Method..  and select unittextui.TestRunner.runFailed(String) and observe that the source code is displayed on the right.


Figure-2.21: Observe source

7. Analyze a couple of more bugs.




                                                                                                              return to top of the exercise


(2.3) Exercise Designation


1. Select Designation and select mostly harmless (or whatever choice of your preference).


Figure-2.22: Designation

2. Save the result.


Figure-2.23: Save result


                                                                                                                        return to top of the exercise

Summary

In this exercise, you learned how to run FindBugs in GUI mode.  You have performed FindBugs operation on JUnit jar file.  You also learned how to add sources to the FindBugs.

                                                                                                                        return to the top



Homework exercise (for people who are taking Sang Shin's "Advanced Java Programming online course")


<tbd>