Most Java developers find static source code analysis tools very handy, PMD, CheckStyle, FindBugs being the most popular amongst them. But all of us, at some time or the other, realise that we need to have some project specific coding conventions being enforced on the developers. This article covers this need and would discuss about writing custom rules with PMD tool.

PMD comes with a set of handy rules, which more than often are sufficient for any project. In fact in many cases we would probably need to exclude some default rules being enforced, to avoid noise in the reports. However, in real life projects you also need some custom rules.

Though custom PMD rules can be written as Java code as well, this article talks about writing them using XPath queries, which is evidently an easier way to adopt. With XPath, we simply write a rule by specifying a code sample and an XPath query to verify that the violation is indeed detected. Of course PMD doesn’t apply the query on the Java code itself but rather on the Abstract Syntax Tree, which is a tree representation of the source code. More details on the AST can be found here.

Thankfully PMD also comes with a visual editor for writing the rules. This tool can be run using the designer.bat under /bin. If you are using Eclipse and have the PMD plugin installed then the designer is accessible under Eclipse Preferences > PMD. Lets now try writing a custom PMD rule. The particular rule we plan to write to enforce the use of StringBuilder instead of StringBuffer (where there are no concurrency issues, of course). For this we first write a code snippet, as follows, in the “Source code” box of the designer.

public class SomeClass {
     //Consider using StringBuilder, if there
     //are no concurrency issues expected
     StringBuffer sb = new StringBuffer("c");

     public void someMethod(){
         //Some code here
         StringBuffer sb = new StringBuffer("d");
     }
}

The next task is to write the XPath expression. Before we do that, we press the “Go” button under “XPath Query” section first. This will generated the corresponding AST in the box and help us write the query well. And since we haven’t written any XPath query as of now, the result section below the “XPath Query” section says “XPath Query field is empty”. Now, we want to detect the presence of a StringBuffer variable, whether at class or method level. If you see the generated AST we can easily detect that the following XPath expression will find the matching lines. We use the @Image attribute to specify the name we want to detect.

//AllocationExpression/ClassOrInterfaceType
[@Image='StringBuffer']

Exporting XPath Rule

If we press the “Go” button again, the results of running the XPath query are displayed in the box below the “XPath Query” section. In our code we should get two matches, and we should see the exact matched strings if we click on the individual lines in the result Pane. We can refine the XPath query this way till we get the exact matches.

Lets now try to write another custom rule. This particular one will report a violation if the developer writes any non static method is a Utils class. We don’t want the Utils class to be instantiated for its methods to be used. Here, we assume that all our Utils class names end with the word “Utils”. As we did last time, we first insert the following code snippet:

public class MyUtils {
      //Any Utility class ending with "Utils" (note, its
      //not "Util") is regarded as a Utils class
      public static void myStaticUtilMethod(String x){
          //this is a static method as expected
      }

      public void myNonStaticUtilMethod(){
          //this method should be static and violates our rule
      }
}

The XPath query in this case, as follows, is quite straight forward. We are only checking for Classes (and skipping Interfaces) that end with the suffix “Utils” and then verify if there are any non-static methods in there. Click the Go button and it should detect a violation as our class does have a non-static method. To verify, change the method signature for myNonStaticUtilMethod() to make it static and press “Go” again. PMD should not report any violation now, confirming that our rule works.

//ClassOrInterfaceDeclaration
[@Interface='false'
and (ends-with(@Image, 'Utils'))
and (count(.//MethodDeclaration) > count(.//MethodDeclaration[@Static='true']))
]

The last step in getting our custom defined rules being used by PMD is to add them to a ruleset. Details on creating your own ruleset are provided here. The designer again will help you in creating the rule XMLs that you can easily copy paste in your ruleset file.

Lets create one for the last custom rule we created. To do this click Actions > Create Rule XML on the designer. You will get a pop-up which will ask you to specify the rule name and any description that goes along. For our ruleset we use the rule name as “OnlyStaticMethodsInUtilsClass” and the message text as “In Utility (ending with ‘Utils’) classes, all methods should be declared static.” which will show up as tool-tip on the IDE with violation report. We may also specify a description. Press “Create Rule XML” button and the designer will do so for you (see the screen grab below).

Exporting XPath Rule

Note that the designer specifies the class for the rule as “net.sourceforge.pmd.rules.XPathRule” on its own. The rule priority is specified at default value of 3, but you can change that. PMD users would know that priority figures of 1 = error, high priority, 2 = error, normal priority, 3 = warning, high priority, 4 = warning, normal priority and 5 = information.

Before PMD could be used with Eclipse it must be imported in your IDE. On Eclipse Preferences under “PMD” select “Import Rule Set”, browse to the ruleset file you saved the custom rules to and you would notice them being imported. Of course, we can use the ruleset from the command line as well from our build script.

With our custom rules, our favourite code quality check tool is now even more useful.