Pmd: [core] How to specify custom path variable and access the value in any rule?

Created on 30 Jan 2017  路  4Comments  路  Source: pmd/pmd

Rule Set:
PMD-JAVA

Description:
I need to be able to customize some values in some rules ( new rules I am working on) using a configuration file, how can I have the file path as command line parameter in run.sh script and then access the value in Java rules.

Sample run command:

./run.sh pmd -d path/to/project -f textcolor -R rulesets/java/design.xml 

I want to achieve something like being able to specify:

./run.sh pmd -d path/to/project -f textcolor -R rulesets/java/design.xml -customization /path/to/file

And get the value of the -customization parameter in one of the rules.

How would you guys recommend me to do it? I need to avoid recompilation of PMD for each configuration change, so I need to access the content of the files at run time. Would appreciate the help! Thanks a lot.

Running PMD through: [CLI]

question

Most helpful comment

@waqas716 then you don't need anything at all. The existing properties support is more than enough for your usecase.

Instead of using a constant, you define a property with a proper type and default value (for instance AvoidDeeplyNestedIfStmtsRule defines an integer property for how many are too many nested ifs). There are property types for pretty much all data types you can think of in the net.sourceforge.pmd.lang.rule.properties package.

Given that, the end user can write a custom ruleset XML including your new rule, passing proper values for the properties, for instance:

<?xml version="1.0"?>
<ruleset name="Custom Properties Java ruleset example"
    xmlns="http://pmd.sf.net/ruleset/1.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd"
    xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd">

  <description>
     Custom ruleset for Java projects
  </description>
  <rule ref="YourRuleSet.xml/YourRuleName">
    <properties>
      <property name="yourPropertyName" value="23" />
    </properties>
  </rule>
</ruleset>

Notice that if the user doesn't define the property (or uses your ruleset directly, without a custom xml) the default value will be used. This is an opt-in for configuration and flexibility, if the defaults work for the user, they don't need to do anything.

When writing unit tests, if you are using pmd-test, you can setup the values to assign to properties in each scenario like this

All 4 comments

@waqas716 well, you would have to add the parameter to PmdParameters, store the values somewhere (typically PmdConfiguration) and then use that configuration during ruleset construction to read the proper values (possibly here)

However, given that rules can be passed properties through the ruleset XML, this is most likely completely unnecessary. What is it exactly that you are trying to achieve?

@jsotuyod Thanks for the help,
_"However, given that rules can be passed properties through the ruleset XML, this is most likely completely unnecessary"_

Exactly, I am hoping to find something easier than what you suggested with _PmdParameters and PmdConfiguration._

What I am trying to achieve is to give users ability to override some threshold values for some rules according to what makes sense for their project without having the need to customise/compile their own pmd.

For example here in GOD Class Rule if user wants to change the value of private static final int FEW_THRESHOLD = 5; to something else like 8 or so, as of now it's not possible (I think) without changing directly in source code and compiling the PMD again to use updated value.

I am creating some rules which use similar constants values but I want to give user ability to override those value by providing a customisation file( json or could be XML if that's easier to work with as you suggested ruleset XML).

I could force them to put on a specific path like ~/pmd-customisation/file.json which is ugly.

@waqas716 then you don't need anything at all. The existing properties support is more than enough for your usecase.

Instead of using a constant, you define a property with a proper type and default value (for instance AvoidDeeplyNestedIfStmtsRule defines an integer property for how many are too many nested ifs). There are property types for pretty much all data types you can think of in the net.sourceforge.pmd.lang.rule.properties package.

Given that, the end user can write a custom ruleset XML including your new rule, passing proper values for the properties, for instance:

<?xml version="1.0"?>
<ruleset name="Custom Properties Java ruleset example"
    xmlns="http://pmd.sf.net/ruleset/1.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd"
    xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd">

  <description>
     Custom ruleset for Java projects
  </description>
  <rule ref="YourRuleSet.xml/YourRuleName">
    <properties>
      <property name="yourPropertyName" value="23" />
    </properties>
  </rule>
</ruleset>

Notice that if the user doesn't define the property (or uses your ruleset directly, without a custom xml) the default value will be used. This is an opt-in for configuration and flexibility, if the defaults work for the user, they don't need to do anything.

When writing unit tests, if you are using pmd-test, you can setup the values to assign to properties in each scenario like this

Thank you for the great answer. That's what I need, perfect!

Was this page helpful?
0 / 5 - 0 ratings