PMD is a static code analysis tool that examines Java source files and can detect potential problems such as code style issues, code defects, race conditions and even security holes. It provides an inexpensive way to avoid the tedium of repeatedly reviewing a large code base. PMD can also find other types of problems, such as, dead code (e.g., assignments to variables that are never subsequently read), performance issues (e.g., misuse of + in StringBuffer assignments, instantiating new objects in loops), style issues (e.g., final static variables should be all caps, unused import statements), and potentially dangerous code practices (e.g., assignments from instance to static field). A frequent and often valid criticism of code analysis tools is that they tend to identify many false positives, which take effort to separate from the actual problems. To address this, PMD can be configured to identify or ignore specific types of issues, and allow individual findings to be ignored as false positives. While PMD can be run from the command-line it is usually invoked from Maven, Ant or your IDE.

Maven

To use PMD in a Maven project, add the following lines to your pom.xml file:

<project>
  ...
    <reporting>
      <plugins>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-pmd-plugin</artifactId>
          <configuration>
            <targetJdk>1.6</targetJdk>
            <rulesets>
              <ruleset>pmd-ruleset.xml</ruleset>
            </rulesets>
          </configuration>
        </plugin>
      </plugins>
    </reporting>
  ...
</project>

Set targetJdk to the version of Java you are coding to, e.g. 1.4, 1.5, or 1.6. The <rulesets> section is optional, but it will make it easy to customize the rules that are applied to your code. You can invoke a PMD analysis with mvn pmd:pmd, or PMD will report its findings as part of the Maven site report (mvn site).

Ant

To use PMD in an Ant project, download PMD and add the following files to a directory in your source tree. I’ll usetools/pmd-4.2.5.

  • lib/
    • asm-3.1.jar
    • jaxen-1.1.1.jar
    • pmd-4.2.5.jar
    • pmd-report.xslt
    • pmd.css
    • pmd-ruleset.xml

If you prefer to keep the PMD libraries outside your source tree, change the locations for either the tools.dir or thepmd.lib.dir properties, or both, in the lines below. Add the following lines to your build.xml file. The values forbuild.dircompile.classpathjunit.lib.dirsrc.dir, and test.src.dir should be set appropriately.

  <property name="tools.dir" location="tools"/>
  <property name="pmd.dir" location="${tools.dir}/pmd-4.2.5"/>
  <property name="pmd.lib.dir" location="${pmd.dir}/lib"/>
  <property name="pmd.ruleset.file" location="${pmd.dir}/pmd-ruleset.xml"/>
  <property name="pmd.xsl.file" location="${pmd.dir}/pmd-report.xslt"/>
  <property name="pmd.css.file" location="${pmd.dir}/pmd.css"/>

  <property name="pmd.build.dir" location="${build.dir}/pmd"/>

  <property name="report.dir" location="${build.dir}/reports"/>
  <property name="pmd.report.dir" location="${report.dir}/pmd"/>

  <path id="test.classpath">
    <path refid="compile.classpath"/>
    <fileset dir="${junit.lib.dir}" includes="**/*.jar"/>
  </path>
  <path id="pmd.classpath">
    <path refid="test.classpath"/>
    <pathelement path="${pmd.build.dir}"/>
    <fileset dir="${pmd.lib.dir}" includes="**/*.jar"/>
  </path>

  <taskdef name="pmd" classname="net.sourceforge.pmd.ant.PMDTask" classpathref="pmd.classpath"/>

  <target name="pmd" description="Analyze the source code with PMD">
    <property name="pmd.report.xml" location="${pmd.report.dir}/pmd.xml"/>
    <mkdir dir="${pmd.report.dir}"/>
    <pmd shortFilenames="true" targetjdk="1.6" rulesetfiles="${pmd.ruleset.file}">
      <formatter type="xml" toFile="${pmd.report.xml}"/>
      <fileset dir="${src.dir}" includes="**/*.java"/>
      <fileset dir="${test.src.dir}" includes="**/*.java"/>
    </pmd>

    <property name="pmd.report.html" location="${pmd.report.dir}/index.html"/>
    <xslt in="${pmd.report.xml}" style="${pmd.xsl.file}" out="${pmd.report.html}"/>
    <copy file="${pmd.css.file}" todir="${pmd.report.dir}"/>
    <echo message="PMD report is at ${pmd.report.html}"/>
  </target>

Use ant pmd to invoke the PMD target and generate XML and HTML reports of the findings.

Customizing the rules

When applying PMD to an established code base, the number of findings can be overwhelming. It is important to prioritize the issues and to eliminate the false positives. Similar to best practices in testing, PMD can be used most effectively when the code is free of findings so that new issues introduced into the source code can be immediately addressed. It is easy to miss significant findings if they are hidden in a list of “expected” findings. You’ll find that some of the PMD rules are stylistic in nature, which is not helpful if PMD’s suggested style doesn’t match your own. Some rules may not apply due to the nature of your application and some violations might be unavoidable due to APIs you are using. In order to get the most value from PMD while keeping the findings manageable, you can customize which rules are run and reported on by editing the pmd-ruleset.xml file. For example, you can comment out all of the rules in the pmd-ruleset.xml file except the <rule ref="rulesets/sunsecure.xml"/>. Running PMD would then examine your code for violations of Sun’s Secure Coding Guidelines only. After looking through the results, you should fix any problems you determine to be legitimate. You can stop PMD from reporting about particular lines of code in future runs by adding an annotation:

// This will suppress UnusedLocalVariable warnings in this class
@SuppressWarnings("PMD.UnusedLocalVariable")
public class Bar {
  void bar() {
    int foo;
  }
}

You can turn off all rules for a single line with the //NOPMD comment, but use it with caution. A rule may be ignored on that line that you were not aware of.

public class Bar {
  // 'bar' is accessed by a native method, so we want to suppress warnings for it
  private int bar; //NOPMD
}

(See Suppressing Warnings for more information.) If you want to ignore all the findings of a particular rule with a ruleset, that rule can be turned off while applying the rest of the ruleset.

  <rule ref="rulesets/junit.xml">
    <exclude name="JUnitAssertionsShouldIncludeMessage"/>
  </rule>

Alternatively, you can enable individual rules without enabling the entire ruleset:

  <rule ref="rulesets/controversial.xml/DontImportSun"/>

As you remedy the findings, you can add other PMD rules to your ruleset. Continue to annotate known false positives and fix the legitimate problems so that all reported findings can be investigated and do not get lost in a long report. Over time, a team can develop a set of rules that it wants to enforce and can use that ruleset on new development projects.

Continuous Integration

Code analysis tools can be thought of as an automated code review that looks for a particular set of issues each time it is invoked. Because it is automated, the associated costs are related to setup and remediation. Once it is up a running, there isn’t much reason not to run it over and over. PMD Trend graph in HudsonDoing a scan of an entire code base is typically slower than convenient in a normal build-test-refactor development cycle, so it may be best to run PMD after a code commit or as an off-hours job. If you use a continuous integration engine, such as Hudson, this is usually as easy as adding a job that invokes the Ant target (pmd) or the Maven goal (pmd:pmd). In particular, Hudson will even provide trending reports of violation counts and severity along with a drilldown to show where the violations are detected within the source code.

Immediate feedback

A good way to get immediate feedback from PMD is to use a plugin for your IDE. PMD has plugins for Eclipse, NetBeans, IntelliJ IDEA and many others. As you edit source code in your IDE, the PMD plugin will highlight any findings in the edited code to give you immediate feedback on violations. Since only modified code is checked, the scan isn’t slow enough to interrupt the rhythm of the build-test-refactor cycle.PMD findings in Eclipse The PMD IDE plugins have their own mechanisms for specifying which rules to run, but they can also be configured to use the same pmd-ruleset.xml file as Maven and Ant. This makes the plugin a good complement to the continuous integration runs. Each developer gets immediate feedback as they code, and then the same rules are applied by the continuous integration engine overnight to catch any findings that may have crept in during integration.

Summary

  • Use PMD to help identify potential coding errors
  • Customize the rules you use to make sure only pertinent rules are applied to your source code
  • Keep the reported violations clear; don’t have “expected” violations. Use annotations or turn off the rule
  • Use a continuous integration engine to periodically run the rules against the entire code base
  • Use an IDE plugin to give immediate feedback to the developer

SecureCI™

SecureCI is a free virtual machine that includes a variety of code analysis tools, including PMD, integrated with Ant and Maven for build-time analysis and Hudson for continuous integration. Other tools in SecureCI include Subversion for source control, Trac for wiki and bug tracking, and ratproxy for security scanning of web applications.

One thought to “Code Analysis with PMD”

Leave a comment

Your email address will not be published. Required fields are marked *

X