PMD is a tool for analysis of Java source code, focusing on detecting possible bugs, dead code, suboptimal code, and overly complex expressions.
To install PMD for use in StackyHack, download the .zip file containing the latest release from the PMD home page into a directory such as "java-lib", and unzip it. Then, define an environment variable called PMD_HOME to point to the distribution directory. For example, "c:\java-lib\pmd-3.7". (Note that the file path should have no embedded spaces in it.)
![]() | Note |
|---|---|
The PMD release used in the following examples is 3.7. If you have downloaded a later release, such as 3.8, you will need to add "-Dpmd.version=3.8" to the command line invocation of Ant to override the default version value in the pmd.build.xml file. | |
Example 4.28, “pmd.build.xml” shows the pmd.build.xml file, which defines the Ant targets used to invoke the PMD tool and the PMD sensor.
Example 4.28. pmd.build.xml
<project name="stackyhack.pmd" default="pmd">
<description>
Provides the PMD tool and the Hackystat PMD sensor.
Note: If you download a different version (say, 3.8), then you can override the default version (3.7) as follows:
ant -Dpmd.version=3.8 -f pmd.build.xml pmd.tool
</description>
<import file="build.xml"/>
<property environment="env"/>
<property name="pmd.dir" location="${build.dir}/pmd" />
<property name="pmd.version" value="3.7"/>
<property name="pmd.jar" value="pmd-${pmd.version}.jar"/>
<target name="pmd" depends="pmd.tool, pmd.report, pmd.sensor" description="Runs the PMD tool, report, and sensor."/>
<target name="pmd.tool" description="Runs PMD over the source code to check for problems.">
<!-- Fail this target if PMD is not installed. -->
<available file="${env.PMD_HOME}/lib/${pmd.jar}" property="pmd.available"/>
<fail unless="pmd.available" message="Error: PMD_HOME not set or ${pmd.jar} not found."/>
<taskdef name="pmd" classname="net.sourceforge.pmd.ant.PMDTask">
<classpath>
<fileset dir="${env.PMD_HOME}/lib" includes="*.jar"/>
</classpath>
</taskdef>
<!-- Run PMD -->
<mkdir dir="${pmd.dir}"/>
<pmd rulesetfiles="basic,braces,clone,codesize,coupling,design,imports,junit,naming,strings"
shortFilenames="false"
targetjdk="1.4"
failuresPropertyName="pmd.failure.count"
failonerror="${pmd.failonerror}"
failOnRuleViolation="${pmd.failonerror}" >
<formatter type="xml" toFile="${pmd.dir}/pmd.xml" />
<fileset dir="${src.dir}" includes="**/*.java" />
</pmd>
</target>
<target name="pmd.report" description="Generates HTML reports on the PMD output.">
<xslt in="${pmd.dir}/pmd.xml" style="${env.PMD_HOME}/etc/xslt/pmd-report-per-class.xslt"
out="${pmd.dir}/pmd-report-per-class.html" />
</target>
<target name="pmd.sensor" description="Sends CodeIssue data to Hackystat using the PMD sensor.">
<!-- Define the pmd sensor taskdef, failing the build if the sensor is not installed. -->
<available classname="org.hackystat.sensor.pmd.PmdSensor" property="pmd.sensor.available"/>
<fail unless="pmd.sensor.available" message="Error: PMD sensor not installed."/>
<taskdef name="hacky-pmd" classname="org.hackystat.sensor.pmd.PmdSensor"/>
<hacky-pmd verbose="${hackystat.verbose.mode}">
<fileset file="${pmd.dir}/pmd.xml"/>
</hacky-pmd>
</target>
<project>
The pmd.build.xml defines the <pmd.tool> target to parse the source code and generate an XML file called pmd.xml containing a report on the problmes encountered. The <pmd.report> target converts the XML file into HTML. The <pmd.sensor> target uses the Hackystat PMD sensor to read in the pmd.xml file generated by PMD and send the CodeIssue data to Hackystat. The <pmd> target simply invokes these three targets in sequence.
Note that when running the PMD tool, you must set the property shortFileNames to false. Otherwise, the data from the PMD tool will not be correctly associated with your Hackystat project.
Example 4.29, “pmd.tool invocation” shows the output from invoking the <pmd.tool> target.
Example 4.29. pmd.tool invocation
C:\svn-csdl\StackyHack>ant -f pmd.build.xml pmd.tool
Buildfile: pmd.build.xml
pmd.tool:
[pmd] edu\hawaii\stack\EmptyStackException.java:15 Avoid variables with short names like e
[pmd] edu\hawaii\stack\Stack.java:62 Consider simply returning the value vs storing it in local variable 'obj'
[pmd] edu\hawaii\stack\Stack.java:91 Avoid empty catch blocks
[pmd] edu\hawaii\stack\TestClearStack.java:18 Private field 'one' could be made final; it is only initialized in the declaration or constructor.
[pmd] edu\hawaii\stack\TestClearStack.java:19 Private field 'two' could be made final; it is only initialized in the declaration or constructor.
[pmd] edu\hawaii\stack\TestClearStack.java:20 Private field 'three' could be made final; it is only initialized in the declaration or constructor.
[pmd] edu\hawaii\stack\TestStack.java:16 Private field 'one' could be made final; it is only initialized in the declaration or constructor.
[pmd] edu\hawaii\stack\TestStack.java:17 Private field 'two' could be made final; it is only initialized in the declaration or constructor.
[pmd] edu\hawaii\stack\TestStack.java:18 Private field 'three' could be made final; it is only initialized in the declaration or constructor.
[pmd] edu\hawaii\stack\TestStack.java:48 Avoid empty catch blocks
BUILD SUCCESSFUL
Total time: 2 seconds
After PMD has been invoked to generate data regarding source code violations, the PMD sensor can be invoked to read in the resulting XML file produced by PMD and send the resulting data to Hackystat as Code Issue sensor data.
To accomplish this, you must first install the PMD sensor, which can process the XML files output by PMD. General instructions on installing sensors are provided in Chapter 2, Client-side configuration: Tool sensor installation; instructions for specific sensors are provided in Chapter 26, Sensors. After installation, your hackyInstaller PMD configuration window should look something like the screen image in Figure 4.18, “ HackyInstaller configuration screen for PMD sensor ”.
Example 4.30, “pmd.sensor invocation” illustrates the invocation of the PMD sensor.
Example 4.30. pmd.sensor invocation
C:\svn-csdl\StackyHack>ant -f pmd.build.xml pmd.sensor Buildfile: pmd.build.xml pmd.sensor: [hacky-pmd] Sensor enabled?: true [hacky-pmd] Processing file: C:\svn-csdl\StackyHack\build\pmd\pmd.xml [hacky-pmd] Hackystat data on 11 Code Issues sent to http://hackystat.ics.hawaii.edu/ (0 secs.) BUILD SUCCESSFUL Total time: 2 seconds
Once you've invoked the sensor, you can verify that this data was received at the server by using the List Sensor Data command. Figure 4.19, “ List Sensor Data with StackyHack PMD data (last three entries) ” illustrates what this page might look like after receiving the StackyHack data from PMD. (Note that the first two entries are from FindBugs; the last three are from PMD.)
A separate CodeIssue sensor data entry is sent for each of the violations detected by PMD, along with supplemental information about the file it was found in and so forth.