Checkstyle, PMD and Findbugs, why and how? - (part 2: PMD)
In the first part of this series, we delved into the importance of code quality in software development and introduced Checkstyle, a tool that streamlines code reviews by enforcing Java coding standards and conventions. We learned how to integrate Checkstyle into our development workflow, create a configuration file, and run checks to identify violations. We also provided a practical example of Checkstyle in action, showcasing its ability to improve code quality by enforcing specific coding standards. Now, armed with Checkstyle, you're better equipped to maintain high code quality in your projects.
For those who haven't yet, you can catch up on Part 1 here: Checkstyle, PMD and Findbugs, why and how? - (Part 1: Checkstyle)
In this second part, we continue our journey by exploring PMD, another invaluable code analysis tool.
PMD: Detecting Code Issues and Potential Vulnerabilities
What is PMD?
In the quest for maintaining high code quality, another indispensable tool is PMD. PMD is an open-source static code analysis tool for identifying potential issues and vulnerabilities in your Java code. It helps in enforcing coding standards and best practices, making it an invaluable addition to your software development workflow.
Why Use PMD?
PMD comes with a wide range of built-in rules to analyze your code for issues such as:
- Code Duplication: PMD can spot duplicated code blocks, helping you refactor and eliminate redundancy in your codebase.
- Complexity: It can detect overly complex methods or classes, encouraging you to break down complex logic into simpler, more manageable components.
- Code Smells: PMD identifies code smells, which are patterns that might indicate design problems or inefficiencies in your code.
- Potential Bugs: PMD can pinpoint potential bugs or issues that might lead to runtime errors or unexpected behavior.
- Coding Standards: It enforces coding standards and conventions to maintain consistency across your project.
Example of PMD
public class OrderProcessor {
private List<Order> orders;
public OrderProcessor(List<Order> orders) {
this.orders = orders;
}
public void processOrders() {
for (Order order : orders) {
if (order.getStatus().equals("Pending")) {
processPendingOrder(order);
} else if (order.getStatus().equals("Shipped")) {
shipOrder(order);
}
}
}
public void processPendingOrder(Order order) {
// Logic to process a pending order
}
public void shipOrder(Order order) {
// Logic to ship an order
}
}
In this revised example, we have a simplified OrderProcessor
class that processes orders based on their status (either "Pending" or "Shipped"). This class provides a clearer illustration of how PMD can identify code issues related to complexity, potential bugs, or coding standards in a real-world context.
How to Set Up PMD
Integrating PMD into your Java project is straightforward:
-
Add PMD Plugin: Begin by adding the PMD plugin to your project's build configuration. If you're using Maven, you can include it in your
pom.xml
:<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-pmd-plugin</artifactId> <version>3.15.0</version> <executions> <execution> <phase>verify</phase> <goals> <goal>pmd</goal> </goals> </execution> </executions> </plugin> </plugins> </build>
-
Configuration: Create a PMD configuration file (e.g.,
pmd.xml
) to specify which rules you want to apply and any custom rulesets.<?xml version="1.0"?> <ruleset name="customruleset"> <description> This ruleset is a start to discover PMD best practices </description> <!-- This rule set enforces best practices for java, official PMD site recommends to start by fixing errors related to this rule set --> <rule ref="category/java/bestpractices.xml"> <exclude name="GuardLogStatement"/> </rule> <rule ref="category/java/codestyle.xml"> <exclude name="CommentDefaultAccessModifier"/> <exclude name="OnlyOneReturn"/> <exclude name="AtLeastOneConstructor"/> </rule> <rule ref="category/java/codestyle.xml/ShortVariable"> <properties> <property name="minimum" value="2"/> </properties> </rule> <rule ref="category/java/codestyle.xml/LongVariable"> <properties> <property name="minimum" value="33"/> </properties> </rule> <rule ref="category/java/codestyle.xml/ShortClassName"> <properties> <property name="minimum" value="3"/> </properties> </rule> <rule ref="category/java/design.xml"> <exclude name="UseUtilityClass"/> <exclude name="LawOfDemeter"/> <exclude name="LoosePackageCoupling"/> </rule> </ruleset>
This is quite a basic example. In case you're interested in seeing more of what PMD can offer in terms of possibilities, you'll be able to find more interesting feature in the following documentation: https://docs.pmd-code.org/latest/pmd_rules_java.html
-
Run PMD: Now, you can run PMD on your code using the following Maven command:
mvn pmd:check
This will analyze your code using the rules defined in your pmd.xml
configuration file.
Customizing PMD Rules and Configurations
PMD's strength lies in its flexibility to tailor code analysis to your project's unique requirements. In your pmd.xml
configuration file, you have the freedom to specify which PMD rules to apply and how strictly they should be enforced. Let's illustrate this with an example:
Suppose you want to focus on enforcing coding standards related to variable naming conventions and code complexity. In your pmd.xml
, you can create a ruleset like this:
<?xml version="1.0"?>
<pmd version="6.0.0" 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>Custom PMD Ruleset</description>
<rule name="VariableNaming" message="Variable names should follow camelCase">
<priority>1</priority>
<properties>
<property name="format">^[a-z][a-zA-Z0-9]*$</property>
</properties>
<description>Ensure variable names follow camelCase convention</description>
<example><![CDATA[
int myVariableName; // Violation: Variable name should be camelCase
int myVariableNameIsFine; // OK: Variable name follows camelCase
]]></example>
<type>VariableNaming</type>
</rule>
<rule ref="category/java/codestyle.xml/ExcessiveMethodLength">
<priority>1</priority>
</rule>
</pmd>
In this example, we've created a custom rule called "VariableNaming" that enforces camelCase variable naming conventions. We've also adjusted the priority to indicate its importance. Additionally, we've included the built-in "ExcessiveMethodLength" rule to catch long methods.
By configuring PMD in this manner, you can fine-tune your code analysis to address specific coding concerns. This level of customization allows you to enforce your coding standards effectively and ensure code quality remains at its peak for your project.
With PMD's ability to adapt to your project's coding standards, it becomes an even more powerful tool in your code quality arsenal.
Conclusion
Code quality is a shared responsibility among all team members involved in software development. Tools like PMD, in addition to Checkstyle, provide a safety net by automating code analysis and helping you maintain coding standards, detect potential issues, and ultimately deliver a more reliable and maintainable software product.
In the next part of this series, we will explore another essential tool in the code quality toolbox: FindBugs. Stay tuned to learn how FindBugs can help identify common bugs and potential issues in your Java codebase.