提高代码质量!详解在Gradle项目中使用PMD的正确姿势

article/2025/9/30 19:48:08

当今的软件开发需要使用许多不同的工具和技术来确保代码质量和稳定性。PMD是一个流行的静态代码分析工具,可以帮助开发者在编译代码之前发现潜在的问题。在本文中,我们将讨论如何在Gradle中使用PMD,并介绍一些最佳实践。

什么是PMD?

PMD是一个用于Java代码的静态代码分析工具。它可以帮助开发者找出潜在的问题,如代码重复、未使用的变量、错误的异常处理等。PMD支持多种规则,可以根据具体项目的需要进行配置。其工作原理参考How PMD Works。

PMD支持通过命令行界面(CLI, Command Line Interface for batch scripting)和其他多种集成方式,比如Maven、Gradle、Java API等等。

PMD在Gradle中配置和使用

Gradle中自带了PMD插件,插件的默认版本可以通过源码DEFAULT_PMD_VERSION知道。使用和配置可以参考The PMD Plugin,页面左上角可以选择Gradle版本,确保查看的版本和你使用的Gradle版本一致,因为很多PMD的配置属性或者功能不一定在每个版本都有。

image-20230409124759078

通过页面左上角选了其他版本后跳转的地址是Gradle文档的首页,而不是PMD插件的文档页。我们可以通过修改The PMD Plugin链接中的8.0.2为其他版本号即可跳转到对应Gradle版本包含的PMD插件文档的页面。比如:

当前最新版:https://docs.gradle.org/current/userguide/pmd_plugin.html

7.3.3版本:https://docs.gradle.org/7.3.3/userguide/pmd_plugin.html

在项目build.gradle文件中增加以下内容应用插件和扩展PMD,参考Usage和Configuration,更多的配置属性可以参考PmdExtension。

plugins {id 'pmd'
}pmd {// 是否将 PMD 结果输出到终端consoleOutput = true// 要使用的PMD版本toolVersion = "6.21.0"// 规则优先级阈值,低于这个优先级则会被忽略rulesMinimumPriority = 5// 使用的规则集配置文件路径ruleSets = ["category/java/errorprone.xml", "category/java/bestpractices.xml"]
}

插件会生成两个主要的PMD TaskpmdMainpmdTest分别对main和test两个项目源文件目录使用PMD进行代码检查。

找到IDEA Gradle窗口 > Tasks > other,双击生成的Task;或者在项目根目录运行./gradlew pmdMain都可以运行PMD。检查结果将输出到终端中(前提是配置了consoleOutput = true),违反了PMD规则的类会给出完整的跳转路径以及规则提示信息。

image-20230409135016234

最后还会给出一个报告的地址,内容包含了输出到终端的信息。Problem列出了规则的提示,点击可以跳转到PMD规则描述文档对应的位置。

image-20230409135722137

Gradle PMD Plugin扩展属性

在这里我们将PMD插件的扩展属性作用进行说明,参考PmdExtension,这个文档详细说明了各个属性的作用、默认值和配置示例。如果文档描述的不是很清楚也可以参考PMD CLI options的对应描述。

consoleOutput

是否将结果输出到终端(System.out)允许值为true|false

ignoreFailures

如果出现了警告,是否允许继续构建,允许值为true|false

配置为否(false),在执行build的时候(build任务中默认包含了pmdMain和pmdTest),如果发现了代码有违反规则,将会中断构建过程;配置为是(true),将不会中断构建,只是输出报告信息。

maxFailures

停止构建前允许的最大失败次数。

incrementalAnalysis

是否开启增量分析,允许值为true|false。在pmd docs Incremental Analysis中详细描述了增量分析的相关信息。简单来说,开启了增量分析,PMD会缓存分析数据和结果,后续分析仅查看那些新的/已更改的文件,以此显著减少分析的时间,在Gradle中,这个功能使用PMD6.0.0及以上版本才有。

但是有一些情况会导致增量分析的缓存失效:使用PMD的版本发生了变化;使用的规则集已更改;被分析的代码的类路径已更改;被分析代码依赖的库的类路径已更改。具体参考When is the cache invalidated?

在以上前提下,即使切换分支缓存也是有效的,甚至还支持在不同的机器重复使用缓存文件。参考Can I reuse a cache created on branch A for analyzing my project on branch B? 和Can I reuse a cache file across different machines?

reportsDir

报告生成的路径。

ruleSetFiles

要使用的自定义规则集文件路径,可以在files()中填多个路径。

ruleSetFiles = files("config/pmd/myRuleSet.xml")

ruleSetConfig

ruleSetFiles的作用一样,不过只能填一个文件路径。

ruleSetConfig = resources.text.fromFile("config/pmd/myRuleSet.xml")

ruleSets

指定使用的规则集,默认值为["category/java/errorprone.xml"]。建议如果配置了ruleSetFiles或者ruleSetConfig,就将ruleSets配置为空(ruleSets = []),以免互相干扰,官方文档Custom ruleset给出的例子也是如此。

ruleSets = ["category/java/errorprone.xml", "category/java/bestpractices.xml"]

rulesMinimumPriority

每个规则都有个优先级,是从 1 到 5 的整数,其中 1 是最高优先级,参考[Message and priority overriding,每个规则的优先级参考Java Rules。rulesMinimumPriority的作用是配置报告的最低优先级,低于这个优先级的规则将被忽略。比如配置rulesMinimumPriority = 4,优先级为 5 的规则将被忽略。

sourceSets

作为 checkbuild 任务的一部分进行分析的源代码集合,配置方式参考SourceSet。

targetJdk

PMD使用的JDK版本。有些规则可能会要求JDK的最低或者最高版本,具体要求参考Java Rules。

threads

PMD 运行时使用的线程数。

toolVersion

要使用的PMD的版本。

为项目自定义合适的规则集

规则分类和查找

PMD能检测的语音有很多种(后面内容以Java为例),针对不同的语音,PMD内置了很多检测规则,并归为了以下几个类别:

  1. 最佳实践(Best Practices):这些规则执行普遍接受的最佳实践。
  2. 代码风格(Code Style):这些规则强制执行特定的编码风格。
  3. 设计(Design):帮助您发现设计问题的规则。
  4. 文档(Documentation):这些规则与代码文档有关。
  5. 容易出错(Error Prone):用于检测损坏、极度混乱或容易出现运行时错误的构造的规则。
  6. 多线程(Multithreading):这些是在处理多个执行线程时标记问题的规则。
  7. 性能(Performance):标记次优代码的规则。
  8. 安全性(Security):标记潜在安全漏洞的规则。

在Java Rules列出了所有相关的规则,点击蓝色字符可以跳转到规则的详细描述页面。

image-20230409200607724

下图是规则AbstractClassWithoutAbstractMethod文档描述的信息,其他规则的描述可能还会包含JDK版本的要求,其他可配置属性等等。

image-20230409200833756

需要注意有的规则可能被标记为Deprecated代表被弃用了。

配置规则集

我们可以编辑XML格式的规则集文件,指定我们项目要执行的规则,参考Making rulesets。下面是没有包含任何规则的规则集文件的模版。

<?xml version="1.0"?><ruleset name="Custom Rules"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 https://pmd.sourceforge.io/ruleset_2_0_0.xsd"><description>My custom rules</description><!-- Your rules will come here --></ruleset>

从上文我们可以知道PMD内置的每个规则都会提供引用实例,我们引用单个规则的时候,只需要将示例的XML代码复制到规则集文件中即可。

<rule ref="category/java/errorprone.xml/EmptyCatchBlock" />

ref中填写的路径category/java/bestpractices.xml/AbstractClassWithoutAbstractMethod我们可以明显看到它是按照内置规则集文件路径/规则名称的格式组织的,一个内置规则集文件对应了一个分类。

我们可以引用内置规则集文件实现批量引入分类下的所有规则,每个分类对应的XML文件名可以参考GitHub pmd-java resources。再通过exclude指定规则的名称来排除某些规则。

<rule ref="category/java/codestyle.xml"><exclude name="WhileLoopsMustUseBraces"/><exclude name="IfElseStmtsMustUseBraces"/>
</rule>

我们可以使用exclude-pattern排除某些文件,使其不被PMD检查,也可以使用include-pattern包含的方式。如果两种方式都包含相同的文件,最终这个文件会被PMD检查。

<?xml version="1.0"?>
<ruleset name="myruleset"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 https://pmd.sourceforge.io/ruleset_2_0_0.xsd"><description>My ruleset</description><exclude-pattern>.*/some/package/.*</exclude-pattern><exclude-pattern>.*/some/other/package/FunkyClassNamePrefix.*</exclude-pattern><include-pattern>.*/some/package/ButNotThisClass.*</include-pattern><!-- Rules here ... --></ruleset>

规则集文件编辑好后,使用ruleSetFiles或者ruleSetConfig配置路径。比如下面配置的意思是指向了项目根目录下的/code-analysis/pmd/rulesets/custom-rule.xml

ruleSetFiles = files("${project.rootDir}/code-analysis/pmd/rulesets/custom-rule.xml"

配置规则

规则引用的同时,我们可以覆盖其原有的一些配置,比如提示消息message和优先级priority

<rule ref="category/java/errorprone.xml/EmptyCatchBlock"message="Empty catch blocks should be avoided" ><priority>5</priority>
</rule>

某些规则可能有特定的属性,我们也可以将其覆盖。这些特定的属性Java Rules中都有提供,比如下面这个例子参考NPathComplexity。

<rule ref="category/java/design.xml/NPathComplexity"><properties><property name="reportLevel" value="150"/></properties>
</rule>

有些属性可以提供多个值,这种情况下可以通过分隔符来提供,比如竖线(|)或逗号(,)。

<property name="legalCollectionTypes"value="java.util.ArrayList|java.util.Vector|java.util.HashMap"/>

抑制警告

有时候PMD可能会产生误报,这种时候我们可以通过抑制警告让PMD跳过对这些代码的检查。

从Java 1.5开始可以使用注解@SuppressWarnings来标记类或者方法。

  • @SuppressWarnings('PMD')抑制所有PMD的警告。
  • @SuppressWarnings("PMD.UnusedLocalVariable")抑制规则UnusedLocalVariable的警告。
  • @SuppressWarnings({"PMD.UnusedLocalVariable", "PMD.UnusedPrivateMethod"})抑规则UnusedLocalVariableUnusedPrivateMethod的警告。
  • @SuppressWarnings("unused")JDK里面的unusedPMD也遵守,抑制所有跟未使用相关的警告。比如:UnusedLocalVariableUnusedPrivateMethod

在警告提示的代码行的末尾加上注释// NOPMD也可以抑制这一行引起的警告,参考NOPMD。

在规则集文件中也可以配置要抑制警告的文件,匹配的方式可以是正则表达式或者XPath,具体可以了解The property violationSuppressRegex和The property violationSuppressXPath。

第三方规则集

除了PMD内置的规则集,我们还可以引入第三方规则集。在3rd party rulesets中列出了一些,还有阿里Java开发规范p3c也基于PMD开发一套规则集,从它的pom.xml可以了解到是基于PMD6.15.0版本。

参考Dependency management引入规则集依赖,在规则集配置中引入提供的规则即可。

dependencies {pmd "com.alibaba.p3c:p3c-pmd:2.1.1"
}

需要注意的是,第三方的规则集很可能没有按照PMD内置规则集那样分类,它们提供的规则配置文件目录也可能不一样,比如p3c的规则配置文件都在/resources/rulesets/目录下并独自定义了一套分类。

其他技巧

PMD的最新官方文档地址是:https://docs.pmd-code.org/latest/pmd_userdocs_tools.html。链接中的latest对应了版本号,指向的是当前最新版本,如果想查看其他版本的文档,修改为对应的版号即可。比如6.39.0版本的链接为:https://docs.pmd-code.org/pmd-doc-6.39.0/index.html。不过可能只有比较新的一些版本才能看到对应的文档。

官方提供了一个PMD的最佳实践可以了解下。

PMD还有跟特定语言相关的文档,比如Java support,里面有支持的JDK版本等信息。

如果使用过程中遇到了问题,可以参考Getting Help从这些网站里面寻找帮助github discussions、github issues、stackoverflow tagged pmd。

PMD官方文档还提供了Copy/Paste Detector (CPD)关信息,CPD可以用于检测重复代码。还提及了Duplicate Code教我们遇到重复代码如何消除,以及一个关于设计模式的网站Design Patterns。

关于PMD这个名字,并没有特殊的含义,作者纯粹只是觉得这几个字母放一起作为名称挺好的,来自What does ‘PMD’ mean?

参考

GitHub - pmd

PMD - docs

Gradle - The PMD Plugin


http://chatgpt.dhexx.cn/article/70n4d4Su.shtml

相关文章

PMD 自定义规则实践入门样例

原文&#xff1a;https://testerhome.com/topics/4918 准备工作 首先在PMD官网下载最新版本的文件&#xff0c;目前最新版本是5.4.1。 下载pmd-bin-5.4.1.zip和pmd-src-5.4.1.zip之后解压备用。 pmd-src-5.4.1是PMD源码包&#xff0c;是无法直接执行的。 pmd-bin-5.4.1是PM…

java pmd 插件下载_sonar-pmd插件集成p3c-pmd

基于官方插件项目sonar-pmd进行改造&#xff0c;这篇文章有详细说明&#xff0c;这个工程有低版本的实现。 每条规则对应的3个配置文件&#xff1a; src\main\resources\org\sonar\l10n\pmd.properties src\main\resources\org\sonar\plugins\pmd\rules.xml src\main\resources…

java pmd eclipse_eclipse插件之Findbugs、Checkstyle、PMD安装及使用

eclipse插件之Findbugs、Checkstyle、PMD安装及使用 一、什么是Findbugs、checkstyle、PMD Findbugs、checkstyle和PMD都可以作为插件插入eclipse&#xff0c;当然也有单独的工具可以实现他们的功能&#xff0c;比如Findbugs Tool就可以不必插入eclipse就可以使用。 三者的功能…

pmd 相机 系统标定

在图像测量过程以及机器视觉应用中&#xff0c;为确定空间物体表面某点的三维几何位置与其在图像中对应点之间的相互关系&#xff0c;必须建立摄像机成像的几何模型,这些几何模型参数就是摄像机参数。在大多数条件下这些参数必须通过实验与计算才能得到&#xff0c;这个求解参数…

DPDK — Userspace PMD 源码分析

目录 文章目录 目录PMD driver 通过 IGB_UIO 与 UIO 进行交互注册一个 UIO 设备PMD 的应用层实现Interrupt DPDK&#xff08;中断模式&#xff09; PMD driver 通过 IGB_UIO 与 UIO 进行交互 IGB_UIO 内核模块的另一个主要功能就是让用于态的 PMD 网卡驱动程序得以与 UIO 进行…

java pmd 安装_PMD-Java代码静态分析工具使用

如今&#xff0c;使用代码分析工具来代替人工进行代码审查&#xff0c;已经是大势所趋了。用于Java代码检测的工具中&#xff0c;不乏许许多多的佼佼者&#xff0c;其中PMD就是其中一款。PMD既可以独立运行&#xff0c;也可以以命令行的形式运行&#xff0c;还可以作为插件在ID…

java pmd 安装_PMD的安装及使用

PMD是一种开源分析Java代码错误的工具。 与其他分析工具不同的是&#xff0c;PMD通过静态分析获知代码错误。也就是说&#xff0c;在不运行Java程序的情况下报告错误。PMD附带了许多可以直接使用的规则&#xff0c;利用这些规则可以找出Java源程序的许多问题。此外&#xff0c;…

java pmd 安装_4. PMD 使用,编译和自定义规则

一 PMD简介 PMD是一款代码静态检查工具,可以检查出很多代码中潜在的bug以及让人感到疑惑的代码,具体大家可以百度下。 二 PMD源代码下载 下载地址: 需要注意的是注意选择branch,一般选择最新的branch;然后可以用git clone下来,或者直接下载zip压缩包。 如下: 从上图也可…

java pmd 插件下载_pmd eclipse插件

PMD是Eclipse上的一款源代码分析插件&#xff0c;与其他分析工具不同的是&#xff0c;PMD通过静态分析获知代码错误。也就是说&#xff0c;它可以在不运行Java程序的情况下报告错误。pmd 支持Java、JavaScript、XML、XSL等&#xff0c;欢迎下载&#xff01; Eclipse PMD插件更新…

java pmd checkstyle_提高代码质量 CheckStyle FindBugs PMD

注&#xff1a;这是一篇翻译文章&#xff0c;原文&#xff1a;How to improve quality and syntax of your Android code&#xff0c;为了理解连贯&#xff0c;翻译过程中我修改了一些陈述逻辑和顺序&#xff0c;同时也加了一些自己的补充。 在这片文章中&#xff0c;我将从工具…

【C语言】 C语言图形编程 俄罗斯方块 课程设计

程序简介 由纯C语言实现的俄罗斯方块小程序&#xff0c;代码长度700行&#xff0c;使用Turbo C图形库美化了界面&#xff0c;并具俄罗斯方块游戏的所有基本功能。玩家可以通过键盘的“上下左右”键移动“方块”&#xff0c;“空格”去翻转方块&#xff0c;每当方块可以将一行“…

简单c语言图形程序设计,c语言实现一些简单图形的打印

1 #define _CRT_SECURE_NO_WARNINGS 1 因为笔者采用的是VS的编译环境所以有了上面的这一句话 我们都知道平面图形是由一条条线段构成,所以我们就先实现线段的打印 1 //打印自定义长度的线段 2 #include 3 intmain() 4 {5 int i = 0; 6 intn; 7 while (~scanf("%d",&…

C语言图形化编程 【二】

C语言图形编程 二 3 基本贴图3.1 声明一个存储图片的变量3.2 图片的路径3.3 显示图片3.4 透明贴图 4 鼠标操作4.1 声明一个存储鼠标信息的变量4.2 获取鼠标4.3 分类讨论鼠标消息的来源 3 基本贴图 3.1 声明一个存储图片的变量 格式: IMAGE img; //类型 变量名(你要贴的图片的…

基于C语言的图形化编程软件,图形化编程工具

原标题:图形化编程工具 1.产品介绍 唯众图形化编程工具是一款基于拖拽式图形化设计的可视化编程工具库,通过拖拽式图形化编程完成程序设计。作为一种易于掌握的图像化编程环境,是编程初学者学习和掌握程序设计方法的有力工具。用图形化编程方式去理解程序语言,可以让学生更…

C语言:编程打印图形

题目 编程打印以下图形: 代码 #include "stdio.h"void main() {char ch = A;int i,j;for(i=

c语言图形时钟编程,c语言程序+图形编程——打造简易的时钟

全程代码小编就在这里发出来了哈,最终的效果图, // c语言+图形编程 电脑时钟 //包含头文件 #include #include #include void Draw_Dial();//绘制静态的表盘 void Draw_Hand(int hour, int minute, int secend); //绘制表针 //主函数 int main() {initgraph

C语言图形编程--俄罗斯方块制作(一)详解

效果图 用C语言实现俄罗斯方块&#xff0c;需要先解决下面几个问题&#xff1a; 1、如何用C语言绘制图形界面 EasyX图形库(http://www.easyx.cn)即TC的图形库在VC下的移植。 包含库#include <graphics.h> 先初始化图形窗口 initgraph(WINDOW_WIDTH, WINDOW_HIGH) ;WINDOW…

C语言图形代码:三角、金字塔、圣诞树、爱心

在C语言的学习过程中&#xff0c;我们熟练掌握循环以后就可以使用循环编写&#xff0c;我们喜欢的图形代码啦&#xff01; 下面我向大家分别展示四种使用C语言循环编写的代码。 后两种都可以用来给自己的女朋友展示喔 1.三角形 2.金字塔 3.圣诞树 4.爱心 &#xff08;1&#…

linux下c语言图形界面实现,「分享」C语言如何编写图形界面

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 贴吧内经常有人问C语言是不是只能用于字符终端界面开发,不能用于图形界面。大家也都有回答,需要其他的库。MFC,GTK,QT。 本人近期刚用GTK库加上纯C写成了第一个LINUX实用程序。现在与大家分享: 主界面程序gmaxtrix.c #includ…

c语言图形时钟编程,c语言+图形编程——打造浅易的时钟

全程代码小编就在这里发出来了哈 // c语言图形编程 电脑时钟 //包罗头文件 #include #include #include #define PI 3.141592654 void Draw_Dial();//绘制静态的表盘 void Draw_Hand(int hour, int minute, int secend); //绘制表针 //主函数 int main() { initgraph(640, 4…