11
votes
  • Java 1.7.0_40
  • Gradle 1.10

I've never used Gradle's PMD plugin and I'm running into trouble trying to add rule sets to my build.gradle. The Pmd documentation is not clear about what the valid values of ruleSets are. Their example is ruleSets = ["basic", "braces"] and they link to the "official list". There's not much to go on, unfortunately.

I was guessing the section title maps to the valid string somehow? Like,

But what about things like "Empty Code (java)"?

Here's a working build.gradle example:

apply plugin: 'java'
apply plugin: 'pmd'

pmd {
    ruleSets = [
            // The first two better work since it's right in the Javadoc...
            "basic",
            "braces",
            // This one does not work and other variations like 
            // "empty code", "emptycode", "empty-code", "empty_code" do not work.
            "emptyCode"
    ]
}
repositories {
    mavenCentral()
}

Gradle spits out the following error:

$ gradle check
:pmdMain FAILED                                                                  

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':pmdMain'.
> Can't find resource emptyCode.  Make sure the resource is a valid file or URL 
    or is on the CLASSPATH.  Here's the current classpath:
    /Users/kuporific/gradle/gradle-1.10/lib/gradle-launcher-1.10.jar

* Try:        
Run with --stacktrace option to get the stack trace. Run with --info or --debug 
    option to get more log output.

BUILD FAILED  

Total time: 9.907 secs

Running with --stacktrace or --debug as suggested doesn't seem to yield anything useful...

Note: create a dummy file like src/main/java/Dummy.java. Otherwise, the build will succeed.

How are ruleSets supposed to be declared?


Edit:

It ended up being easier declaring an xml rule set because it offers fine-grained control over the rules. It is included in build.gradle like so:

apply plugin: 'pmd'

pmd {
    ruleSetFiles = files('path/to/ruleSet.xml')
}

And the rule set file looks something like this:

Note: This exaple is written for Gradle 1.10. Newer versions of Gradle (circa 2.0) use a newer version of PMD; therefore, many of the rulesets paths changed. So rulesets/logging-java.xml is now found in rulesets/java/logging-java.xml, for example.

<?xml version="1.0" encoding="UTF-8"?>
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    name="Android Application Rules"
    xmlns="http://pmd.sf.net/ruleset/1.0.0"
    xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd"
    xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 
                        http://pmd.sf.net/ruleset_xml_schema.xsd" >

    <rule ref="rulesets/logging-java.xml" />
    <rule ref="rulesets/basic.xml" />
    <rule ref="rulesets/braces.xml" />
    <rule ref="rulesets/codesize.xml" >
        <exclude name="TooManyMethods" />
    </rule>
    <rule ref="rulesets/controversial.xml">
        <exclude name="UseConcurrentHashMap" />
        <exclude name="AvoidLiteralsInIfCondition" />
        <exclude name="DataflowAnomalyAnalysis" />
        <exclude name="CallSuperInConstructor" />
        <exclude name="AtLeastOneConstructor" />
        <exclude name="NullAssignment" />
    </rule>
    <!-- etc... -->
</ruleset>
4

4 Answers

6
votes

I realize this is a huge edit, but it's essentially a different answer. So after speaking to you and playing around with it, I've determined that the Gradle plugin uses a slightly older version of the pmd library than is published (namely, version 4.3); however, there are a few rulesets missing from the plugin since the most recent pmd version is 5.0.5 which breaks with a NullPointerException with Gradle and Java. Now, after writing possibly the most syntactically correct and painstaking Hello World Java program of my life to test all of these, I've compiled every single Java rule-set that works with the Gradle plugin at the moment:

here's the Main.java:

package william;
import java.util.logging.Logger;

public final class Main{
    private Main(){}
    public static void main(final String [ ] args){
        final Logger log = Logger.getLogger(Main.class.getName());
        log.fine("Hello World");
    }
}

here's the build.gradle:

apply plugin: 'java'
apply plugin: 'pmd'

pmd {
    ruleSets = [
            "basic",
            "braces",
            "naming",
            "android",
            "clone",
            "codesize",
            "controversial",
            "design", 
            "finalizers",
            "imports",
            "j2ee",
            "javabeans",
            "junit",
            "logging-jakarta-commons",
            "logging-java",
            "migrating",
            "optimizations",
            "strictexception",
            "strings",
            "sunsecure",
            "typeresolution",
            "unusedcode"
            ]
}
repositories {
    mavenCentral()
}

and now you might be wondering, which rulesets AREN'T supported yet? well the answer is:

  1. "comments"
  2. "empty"
  3. "unnecessary"

Trust me when I say, the rest of the rules work flawlessly. They tore me apart when writing a Hello World. So, I hope this helps, the directory that has all of the Java rulesets.xml files defined is at: link to pmd's github java ruleset directory I ignore the migrate ones, because they didn't work. I think they're for something specific.

Good luck, and I would bring up the issue of the missing rulesets on the gradle forums to petition to get them added, or update the version. Or you could custom compile the plugin and link it to the newer pmd version if you are really desperate for the missing rulesets.

20
votes

The latest version of PMD (5.1.3 when writing this answer) is supported by gradle. The rulesets need to be prefixed by a java-

I tested this with gradle-1.12

To use PMD 5.1.3 with gradle, the following configuration defines all the possibles rulesets I could find:

pmd {
    toolVersion = '5.1.3'
    ruleSets = [
            'java-android',
            'java-basic',
            'java-braces',
            'java-clone',
            'java-codesize',
            'java-comments',
            'java-controversial',
            'java-coupling',
            'java-design',
            'java-empty',
            'java-finalizers',
            'java-imports',
            'java-j2ee',
            'java-javabeans',
            'java-junit',
            'java-logging-jakarta-commons',
            'java-logging-java',
            'java-migrating',
            'java-naming',
            'java-optimizations',
            'java-strictexception',
            'java-strings',
            'java-sunsecure',
            'java-typeresolution',
            'java-unnecessary',
            'java-unusedcode'
            ]
}

Reference: http://forums.gradle.org/gradle/topics/_pmdtest_fails_with_cant_find_resource_null_when_rulesets_include_braces_gradle_2_0_rc_1

6
votes

To add to the other excellent answers here. After applying pmd to your gradle build and invoking it via gradle pmdMain, the pmd jar will be downloaded to your gradle cache. From there you can run:

find ~/.gradle -name "*pmd*.jar" -exec jar -tvf {} \;|grep rulesets

And you will get the output:

0 Thu Nov 10 20:48:06 EST 2011 rulesets/
     0 Thu Nov 10 20:48:06 EST 2011 rulesets/internal/
     0 Thu Nov 10 20:48:06 EST 2011 rulesets/releases/
 18068 Thu Nov 10 20:48:06 EST 2011 rulesets/naming.xml
    65 Thu Nov 10 20:48:06 EST 2011 rulesets/jsprulesets.properties
   710 Thu Nov 10 20:48:06 EST 2011 rulesets/migrating_to_15.xml
   483 Thu Nov 10 20:48:06 EST 2011 rulesets/migrating_to_14.xml
  1048 Thu Nov 10 20:48:06 EST 2011 rulesets/rulesets.properties
  3017 Thu Nov 10 20:48:06 EST 2011 rulesets/javabeans.xml
  2089 Thu Nov 10 20:48:06 EST 2011 rulesets/sunsecure.xml
   777 Thu Nov 10 20:48:06 EST 2011 rulesets/migrating_to_junit4.xml
  3198 Thu Nov 10 20:48:06 EST 2011 rulesets/scratchpad.xml
 13190 Thu Nov 10 20:48:06 EST 2011 rulesets/strings.xml
  1379 Thu Nov 10 20:48:06 EST 2011 rulesets/internal/all-java.xml
  2639 Thu Nov 10 20:48:06 EST 2011 rulesets/internal/dogfood.xml
  6036 Thu Nov 10 20:48:06 EST 2011 rulesets/finalizers.xml
  5347 Thu Nov 10 20:48:06 EST 2011 rulesets/logging-jakarta-commons.xml
 13629 Thu Nov 10 20:48:06 EST 2011 rulesets/migrating.xml
   610 Thu Nov 10 20:48:06 EST 2011 rulesets/migrating_to_13.xml
  3593 Thu Nov 10 20:48:06 EST 2011 rulesets/braces.xml
  4163 Thu Nov 10 20:48:06 EST 2011 rulesets/clone.xml
   702 Thu Nov 10 20:48:06 EST 2011 rulesets/releases/33.xml
  1332 Thu Nov 10 20:48:06 EST 2011 rulesets/releases/41.xml
  1009 Thu Nov 10 20:48:06 EST 2011 rulesets/releases/35.xml
   395 Thu Nov 10 20:48:06 EST 2011 rulesets/releases/43.xml
  1340 Thu Nov 10 20:48:06 EST 2011 rulesets/releases/40rc1.xml
  1110 Thu Nov 10 20:48:06 EST 2011 rulesets/releases/34.xml
   537 Thu Nov 10 20:48:06 EST 2011 rulesets/releases/38.xml
   346 Thu Nov 10 20:48:06 EST 2011 rulesets/releases/37-jsp.xml
   393 Thu Nov 10 20:48:06 EST 2011 rulesets/releases/37.xml
   744 Thu Nov 10 20:48:06 EST 2011 rulesets/releases/39.xml
  1066 Thu Nov 10 20:48:06 EST 2011 rulesets/releases/36.xml
  1256 Thu Nov 10 20:48:06 EST 2011 rulesets/releases/42.xml
  6379 Thu Nov 10 20:48:06 EST 2011 rulesets/android.xml
  4967 Thu Nov 10 20:48:06 EST 2011 rulesets/logging-java.xml
 11557 Thu Nov 10 20:48:06 EST 2011 rulesets/j2ee.xml
 52926 Thu Nov 10 20:48:06 EST 2011 rulesets/design.xml
  9216 Thu Nov 10 20:48:06 EST 2011 rulesets/basic-jsp.xml
 37773 Thu Nov 10 20:48:06 EST 2011 rulesets/basic.xml
  3981 Thu Nov 10 20:48:06 EST 2011 rulesets/imports.xml
  3836 Thu Nov 10 20:48:06 EST 2011 rulesets/typeresolution.xml
  2755 Thu Nov 10 20:48:06 EST 2011 rulesets/unusedcode.xml
 25043 Thu Nov 10 20:48:06 EST 2011 rulesets/controversial.xml
  3045 Thu Nov 10 20:48:06 EST 2011 rulesets/coupling.xml
 13379 Thu Nov 10 20:48:06 EST 2011 rulesets/strictexception.xml
 12787 Thu Nov 10 20:48:06 EST 2011 rulesets/codesize.xml
 12484 Thu Nov 10 20:48:06 EST 2011 rulesets/junit.xml
 10784 Thu Nov 10 20:48:06 EST 2011 rulesets/optimizations.xml
  1412 Thu Nov 10 20:48:06 EST 2011 rulesets/basic-jsf.xml
  1396 Thu Nov 10 20:48:06 EST 2011 rulesets/favorites.xml

These may not all be implemented, but it is a good starting point. For a description of each file, you can check the documentation here.

1
votes

When using your own rulset.xml file as described by kuporific, like:

pmd {
ruleSetFiles = files('path/to/ruleSet.xml')
}

gradle 1.10 uses some kind of default rules. Yes it does complain if the filepath is wrong, yes it complains if the contents are invalid. But during the checks some default ruleset will be applied. So I'm kind of suprised this worked for you.

Also see: http://forums.gradle.org/gradle/topics/with_gradle_1_5_pmd_applying_basic_rules_even_when_they_are_not_included_in_our_rule_set_files

Workaround is not to use ruleSetfiles, but reference them one by one:

ruleSets = [ "$projectRoot/buildtools/pmd-rules/strings.xml"]