h5. Introduction The Java code quality toolbox contains a lot of excellent, open source software. PMD is a tool that checks your Java source code against a set of rules and reports any discrepancies it finds. This blog entry contains an introduction to PMD and examples of how to write your own rules in Java and XPath. h5. What is PMD? [PMD | http://pmd.sourceforge.net] is a static analysis tool. What this means is that PMD works by inspecting source code, whereas eg. JUnit works by actually running your code. PMD converts each Java source file into a so-called Abstract Syntax Tree (AST), which is a tree representation of the source. This tree is then examined by PMD rules, which look for unwanted patterns in the code. One rule might, for instance, look for while loops whose loop bodies are not enclosed in braces. Another rule might look for collections that are being iterated over without the use of the for (Iterator i = collection.iterator(); i.hasNext(); ) idiom. PMD comes with a number of useful rules grouped into rule sets. For more information on the built-in rule sets, please refer to the PMD homepage. h5. Using the Rule Designer utility In order to write PMD rules, you need to understand how to navigate the Abstract Syntax Tree. The Rule Designer is a handy utility that lets you convert an arbitrary Java class into an AST. Run the Rule Designer by executing bin\designer.bat below the PMD directory, type in or paste the Java code you want to analyse and click "Go". Here's an example: h5. Writing a PMD rule PMD rules traverse the AST using the visitor design pattern (http://en.wikipedia.org/wiki/Visitor_pattern). Each node in the AST accepts visitor objects. When a visitor is passed to a node, the node calls the visit method on the visitor, handing it a reference to itself. The node's class determines which of the several overloaded visit methods will be called on the visitor object. In practice, new PMD rules extend the net.sourceforge.pmd.AbstractRule class. AbstractRule contains a number of overloaded visit methods, inherited from net.sourceforge.pmd.ast.JavaParserVisitorAdapter . When writing a new rule, you only need to override the methods that handle the nodes that are relevant to the rule. Let's write a new rule. The purpose of our rule is to ensure that the names of class constants (ie. fields that are static and final) consist of only uppercase letters and the underscore character. By taking a closer look at the Rule Designer example above, we learn that we need to visit all FieldDeclarator nodes in the AST. This means we need to override the visit(ASTFieldDeclaration node, Object data) method in our rule class. The complete source code of the rule follows below. DISCLAIMER : Please note that the following source code is provided for educational purposes +only+. It is +not+ intended for production use. UpperCaseConstantsRule.java package dk.applicon.java.pmd.rules; import net.sourceforge.pmd.AbstractRule; import net.sourceforge.pmd.ast.ASTFieldDeclaration; public class UpperCaseConstantsRule extends AbstractRule { private static final String CONSTANT_NAME_PATTERN = "[A-Z]+(?:_[A-Z]+)*"; public Object visit(ASTFieldDeclaration node, Object data) { if (node.isFinal() && node.isStatic()) { // The field is static and final String name = node.getVariableName(); if (!name.matches(CONSTANT_NAME_PATTERN)) { // Add a rule violation to the report addViolation(data, node); } } return super.visit(node, data); } } The code is pretty straightforward. The return statement, though, might not make immediate sense. By calling the overridden visit method in the superclass, we make sure that children of the current node are also visited. h5. Creating a ruleset XML document h5. Running PMD We're now ready to run PMD. Assuming that the rule class is in your class path, run the pmd.bat script as follows: The first parameter is the name of a source file or a directory of source files. The second parameter is the report format. The third parameter is the name of the ruleset XML document. In this example, I'm running the newly created rule against its own source code. The UpperCaseConstantsRule class does contain a class constant, but the name does not violate the rule. Let's change that: private static final String constantNamePattern = "[A-Z]+(?:_[A-Z]+)*"; Running PMD again, we now get an error report indicating a problem on line 8 of UpperCaseConstantsRule.java :