Recently I tried out three popular Java code scan tools:
- PMD
- CheckStyle
- SpotBugs (the successor of FindBugs).
PMD
PMD is straightforward to use.
/programs/pmd/bin/run.sh pmd -d /file/path/com/foo/Bar.java -format xml -rulesets pmd_rulesets.xml -language java
The scan result is returned in console as:
<?xml version="1.0" encoding="UTF-8"?>
<pmd version="5.8.1" timestamp="2017-09-21T12:44:22.940">
<file name="/file/path/com/foo/Bar.java">
<violation beginline="225" endline="241" begincolumn="9" endcolumn="9" rule="ConfusingTernary" ruleset="Design"
package="com.foo" class="Bar" method="getSomething" externalInfoUrl="https://pmd.github.io/pmd-5.8.1/pmd-java/rules/java/design.html#ConfusingTernary" priority="3">
Avoid if (x != y) ..; else ..;
</violation>
</file>
</pmd>
CheckStyle
CheckStyle is fairly straightforward to use. Tweak the style check file (sun_checks.xml) to your liking, then:java -jar /some/path/checkstyle-8.2-all.jar -c /somelocation/sun_checks.xml -f /file/path/com/foo/Bar.java
This produces the xml scan result in console.
<?xml version="1.0" encoding="UTF-8"?>
<checkstyle version="8.2">
<file name="/file/path/com/foo/Bar.java">
<error line="100" column="5" severity="warning"
message="Missing a Javadoc comment." source="com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocMethodCheck"/>
</file>
</checkstyle>
To link to CheckStyle web site for the explanation of the rule, you can map
com.puppycrawl.tools.checkstyle.checks.{ruleset}.{rule}Check
to
http://checkstyle.sourceforge.net/config_{ruleset}.html#{rule}
For example, for the rule
com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocMethodCheck
we have
http://checkstyle.sourceforge.net/config_javadoc.html#JavadocMethod
SpotBugs
SpotBugs vs FindBugs makes another forking episode in Open Source. While FindBugs is still well alive, the force seems be with SpotBugs at this moment. Unlike PMD or CheckStyle, SpotBugs works on the binaries. It is a little harder to cajole, but definitely worth it.
# The classes to be analyzed
SCAN_LIST='com.foo.Bar,com.foo.Goo'
# Add the jars needed by spotbugs to classpath
export CLASSPATH=/programs/spotbugs/libs/*:$CLASSPATH
# Auxiliary jar list
AUX_JARS='/path/aux_jars.txt'
ls /mywebapp/WEB-INF/lib/* > $AUX_JARS
/programs/spotbugs/bin/spotbugs -textui -progress -dontCombineWarnimlngs -xml:withAbridgedMessages -output /somewhere/output.xml -onlyAnalyze SCAN_LIST -maxHeap 2100 -auxclasspathFromFile $AUX_JARS /mywebapp/WEB-INF/classes
Whatever I do, I cannot make auxclasspath take a directory. So I end up adding each jar inside WEB-INF to auxclasspath.
With xml output, there are a few additional options to tweak the report:
- xml:withAbridgedMessages, java classes and methods are referred to using abridged names instead of fully qualified names. For example, "Bar.SOME_CONST should be package protected." Personally, I like this option.
- xml:withMessages, detailed messages are given in each bug instance. For example, "com.foo.Bar.SOME_CONST should be package protected."
- xml:minimal, suppress all messages and statistics report.
To link to SpotBugs web site for each violation details, note the bug instance type
<BugInstance type="MS_PKGPROTECT" priority="2" rank="18" abbrev="MS" category="MALICIOUS_CODE" instanceHash="fd540b76c1396830548e4c94bbd3c94" instanceOccurrenceNum="0" instanceOccurrenceMax="0" cweid="218">
This should be linked to
http://spotbugs.readthedocs.io/en/latest/bugDescriptions.html#MS_PKGPROTECT