XPath – how to create a custom rule

By , last updated November 28, 2019

After I began to use PMD and tried to write my first custom XPath rules, I realised that there aren’t very much information about it. So I needed to figure out almost everything by myself. Here I’ll try to explain what I’ve figured out.

I use Eclipse 3.5 to run the rules, by the way.

1. Create a new ruleset file as described here.
2. Check if you need a special encoding for the language you are going to use. I was using a norwegian language, so I needed to add encoding=”ISO-8859-1″ to xml header:

<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>
...

3.Begin writing a custom rule:

<rule name="MoreThanOneLoggUtil"
      message="You are using more that one LoggUtil instance. Only one is legal."
      class="net.sourceforge.pmd.rules.XPathRule"
      externalInfoUrl="">
<description>
   You are using more that one LoggUtil instance. Only one is legal.
</description>
<priority>4</priority>
<properties>
   <property name="xpath">
       <value>
          ... (some XPath code here) ...
       </value>
   </property>
</properties>
<example>
<![CDATA[
public class Foo
     private LoggUtil log = new LoggUtil(Foo.class);
     private LoggUtil log2 = new LoggUtil(Foo.class);
]]>
</example>
</rule>

4. Fill inn XPath code.

XPath code starts with CDATA-tag:

<![CDATA[
   ...
]]>

Then you fill inn the main identifier, f.ex.:

<![CDATA[
   //ClassOrInterfaceBodyDeclaration
   [
      ...
   ]
]]>

The most important thing here is that it’s legal to use only ONE main identifier with annotation “//”. If you want to implement a complex logic you need to write it within [] braces.

Here we are going to count how many LoggUtil instances does the class have, så vi use a count() function and “VariableDeclarator”-identifier::

count(//VariableDeclarator[../Type/ReferenceType/ClassOrInterfaceType[@Image='LoggUtil']])>1

So the end custom rule here will look like this:

<rule name="MoreThanOneLoggUtil"
      message="You are using more that one LoggUtil instance. Only one is legal."
      class="net.sourceforge.pmd.rules.XPathRule"
      externalInfoUrl="">
<description>
   You are using more that one LoggUtil instance. Only one is legal.
</description>
<priority>4</priority>
<properties>
   <property name="xpath">
       <value>
          <![CDATA[
            //ClassOrInterfaceBodyDeclaration
            [
               count(//VariableDeclarator[../Type/ReferenceType/ClassOrInterfaceType[@Image='LoggUtil']])>1
            ]
          ]]>
       </value>
   </property>
</properties>
<example>
<![CDATA[
public class Foo
     private LoggUtil log = new LoggUtil(Fooclass);
     private LoggUtil log2 = new LoggUtil(Foo.class);
]]>
</example>
</rule>

Look here for more examples.

Senior Software Engineer developing all kinds of stuff.