Custom Java PMD rule: Can't find the class Cus

2019-05-29 01:40发布

问题:

I'm trying to write custom PMD rules in Java. I have created a custom ruleset that looks like this:

<?xml version="1.0"?>
<ruleset name="Custom Ruleset" 
    xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd">

    <description>
        My custom rules
    </description>
    <rule name="CustomRule"
        message="Custom message"
        class="mwe.CustomRule">
        <description>
            Custom description
        </description>
        <priority>3</priority>
    </rule>

</ruleset>

I call pmd.bat using this Java class:

package mwe;

import java.io.IOException;
import java.io.InputStream;
import java.util.Scanner;

public class PmdStarter {

    public static void main(String[] args) {
        callPmd();
    }

    public static void callPmd() {
        String pmdPath = "pmd-src-5.0.5/bin/pmd.bat";
        String checkThisCode = "checkThisCode/";
        String customRuleSet = "pmd-src-5.0.5/src/main/resources/rulesets/java/customRules.xml";
        String[] command = { pmdPath, "-dir", checkThisCode, "-rulesets",
                customRuleSet };

        ProcessBuilder pb = new ProcessBuilder(command);

        try {
            InputStream is = pb.start().getInputStream();
            String output = convertStreamToString(is);
            is.close();
            System.out.println(output);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    static String convertStreamToString(InputStream is) {
        Scanner s = new Scanner(is);
        s.useDelimiter("\\A");
        String streamContent = s.hasNext() ? s.next() : "";
        s.close();
        return streamContent;
    }
}

Unfortunately my custom rule written in Java can't be found; this is the message from PmdStarter:

Couldn't find the class mwe.CustomRule

This is my (minimal) custom rule:

package mwe;

import net.sourceforge.pmd.lang.java.ast.ASTWhileStatement;
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;

public class CustomRule extends AbstractJavaRule {

    public Object visit(ASTWhileStatement node, Object data) {
        System.out.println("Hello PMD");
        return data;
    }
}

This is my project structure in Eclipse:

I have read here that this sort of error seems to be a classpath error. After reading this I have placed CustomRule.class in a couple of directories within the project, hoping in vain that PMD would find it.

My question is: How can I make PMD execute my CustomRule?

回答1:

I've found a way: PMD will find your rule if you put it in a jar and place that jar in pmd-src-5.0.5\lib.

This is the shell command I use to make my rule accessible to PMD (my rules are in package mwe). Note that this is issued from my projects bin folder:

C:\Users\me\dev\CodeCheckerMWE\bin>jar -cf ..\pmd-src-5.0.5\lib\myrules.jar mwe

I have experimented with the classpath and the -auxclasspath option of PMD to make it accept different locations but with no success.

If anyone has a different (preferably more elegant) solution to this, please let me/us know.



回答2:

By the way, for anyone else having problems, it looks like the instructions under http://pmd.sourceforge.net/snapshot/customizing/howtowritearule.html are outdated.

  • You need to add a description to the first child of the ruleset tag

    <description> Avoid using 'while' statements without using curly braces </description>

  • The syntax for actually running pmd seems to have changed, e.g.

./run.sh pmd -d /home/markus/project/src/de/ -f xml -R /home/markus/project/myrules.xml

  • You need to put the jar containing the java rule class under the lib folder of extracted binary zip of PMD. (See answer from Matthias Braun)