4. PMD 使用,编译和自定义规则

  1. 云栖社区>
  2. 博客>
  3. 正文

4. PMD 使用,编译和自定义规则

技术小胖子 2017-11-09 14:35:00 浏览1443
展开阅读全文

一 PMD简介

PMD是一款代码静态检查工具,可以检查出很多代码中潜在的bug以及让人感到疑惑的代码,具体大家可以百度下。


二 PMD源代码下载


下载地址:


https://github.com/pmd/pmd/tree/pmd/5.5.x


需要注意的是注意选择branch,一般选择最新的branch;然后可以用git clone下来,或者直接下载zip压缩包。

spacer.gif

如下:

wKiom1kMd3uwVf_zAACLS5WiwjU978.png-wh_50


从上图也可以看到,pmd支持的语言有很多,java的检测那就是在pmd-java里面。


三 maven下载和环境变量配置


参考网址:

http://blog.csdn.net/jiuqiyuliang/article/details/45390313


  1. 下载maven

    地址:maven下载

  2. 配置MAVEN_HOME和path

  3. 检测maven环境:开始菜单->运行->cmd->mvn -v

如下图:

wKiom1kMeMqgBnOEAABF_jsx5Ww771.png-wh_50


四 配置JDK

这个网上资料太多了,就不细说了, 比如:

http://www.cnblogs.com/smyhvae/p/3788534.html


五 编译PMD


  1. 在home目录配置 ~/.m2/toolchains.xml 这里我发现分两种情况:

    第一种,我在本地装了git bash,所以打开git bash后,敲入cd ~,如下图:

  

  wKioL1kNJeXC3OE2AAARWJ6Kpv8807.png-wh_50



  那这种的话直接在c/users/rongwei.huang目录创建./m2/toolchains.xml文件

  可以把PMD源代码目录下example-toolchains.xml文件拷贝过去,改成toolchains.xml


  如下:

  wKiom1kNJqKjj2xYAAA-NLqBC2g307.png-wh_50

 


  wKioL1kNJ3DhsnAqAAAOnXbyM1A511.png-wh_50


  修改toolchains.xml,主要就是配置JDK版本和路径,我使用JDK1.8编译,所以配置如下:


 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="UTF8"?>
<toolchains>
  <!-- place this file in ${user.home}/.m2/toolchains.xml -->
  <!-- adjust the paths to jdkhome -->
 
  <toolchain>
    <type>jdk</type>
    <provides>
      <version>1.8</version>
    </provides>
    <configuration>
      <jdkHome>/path/to/jdk/1.8</jdkHome>                                                   <!-- Linux -->
      <jdkHome>/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home</jdkHome>    <!-- MacOSX -->
      <jdkHome>h:\\Android\\jdk1.8.0_25</jdkHome>                                     <!-- Windows -->
    </configuration>
  </toolchain>
</toolchains>

  

  

 第二种,就是没有安装类似git bash这种linux环境软件,这种我没有试过,别的帖子有介绍:

 PMD编译



2. 编译PMD源代码

配置完toolchains.xml之后,在PMD源代码目录打开命令行,执行


mvn clean package


如下图:

wKioL1kNKVOgoB1nAABX6v6N8nI764.png-wh_50


3. 编译遇到问题

在编译的时候,我遇到下面两个问题:

a. java doc 编译失败

可以参考这篇帖子解决方法: PMD Java doc '->'编译失败


b. 测试项EcmascriptTokenizerTest没有通过

我直接把它注释掉了


4. 编译成功,查看结果

wKioL1kNKuOwX7xwAABtAtnuXGU333.png-wh_50


在PMD源代码pmd-dist目录,target文件夹查看zip文件


wKiom1kNKy-y3rJeAAAorkYbvYs397.png-wh_50


5. 解压PMD

拷贝pmd-bin-5.5.8-SNAPSHOT.zip到一个没有中文字符的路径,然后解压。


解压后,主要包括bin和lib两个文件夹

bin是可执行程序,下面我们会用里面的程序编写自定义规则。

lib包含很多jar包,jar包里面包含规则的实现以及描述的xml文件。


wKiom1kNLFXRRbwvAAAROqI9DTQ821.png-wh_50



六 自定义PMD规则


可以参考这篇帖子: 自定义PMD规则, 不过也说说自己的操作方法


  1. eclipse打开PMD源代码工程

  为了写代码方便一点,可以用Eclipse来打开,具体是:

  File->New->Java Project->去掉Use default location->选择PMD的源代码路径->finish


  wKioL1kNMAjhEi75AAAX7BTiYA0125.png-wh_50


2. 创建规则检测类


在java规则里面创建一个新的规则类WhileLoopMustUseBracesRule.java,继承自AbstractJavaRule.java


路径:

pmd-source\pmd-java\src\main\java\net\sourceforge\pmd\lang\java\rule\


如上面那个帖子说的,我们要创建一个规则检测java代码while循环必须有{}

也就是这种写法是错误的:

while(condition)

  i++;

需要改成这样

while(condition) {

  i++;

}


所以,我们需要一个类来检测它。


如下:

wKiom1kNMlSSqapJAACsT-fvzDc276.png-wh_50


这个类主要重写了检测方法visit,至于为什么这么写,可以参考上面这个帖子:自定义PMD规则



3. 创建描述性xml

在pmd-source\pmd-java\src\main\resources\rulesets\java\目录下创建自定义规则的描述性xml,在这个目录可以看到很多已经有的xml,比如:


wKioL1kNMy3iWJKyAAAgr_s2ytA007.png-wh_50



其中android.xml表示的是针对android的检测,basic.xml表示基本通用的检测。


那我们也可以把basic.xml拷贝一份,改成自定义的xml,比如mycustomrules.xml


如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?xml version="1.0"?>
 
<ruleset name="mycustomrule"
    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 rule</description>
 
    <rule name="WhileLoopsMustUseBracesRule"
          language="java"
          since="5.6"
          message="while loop must has braces as first element you are in error!!!"
          class="net.sourceforge.pmd.lang.java.rule.WhileLoopMustUseBracesRule"
          externalInfoUrl="${pmd.website.baseurl}/rules/java/basic.html#JumbledIncrementer">
     <description>while loop must has braces as first element</description>
     <priority>3</priority>
     <example>
 <![CDATA[
class Example {
 
  void bar() {
     while(baz)   //need has {}
        buz.doSomething();
  }
}
 ]]>
     </example>
     </rule>
</ruleset>


上面有几个描述性信息:

description: 自定义规则描述

rule name: 名称

language: java

since: 表示从哪个pmd版本开始有这个规则

message: 用来提示用户出错的描述性信息

class: 表示具体用来检测的类,也就是我们自定义的那个类

externalInfoUrl: 在生成的html报告中,用来给用户点击跳转到帮助页面的链接。在帮助页面有这个错误的更详细的描述信息;

description: 出错描述

priority: 优先级

example: 出错示例



4. 编译打包

在PMD源代码下面的pmd-java目录,打开命令行,执行


mvn clean package


wKioL1kNNdOQreANAAAxu0BXbVM170.png-wh_50


在编译目录pmd-source\pmd-java\target\下查看编译结果


pmd-java-5.5.8-SNAPSHOT.jar


可以用压缩工具查看这个jar是否包含了我们自定义的xml和java文件


wKioL1kNNzDAXZjWAACMotDCERk429.png-wh_50



wKiom1kNN2GiLpzJAACbyJ0quK4499.png-wh_50



5. 拷贝生成的jar到PMD-bin解压目录


在上面第五步,我们编译了PMD源代码,并且生成了pmd bin压缩包。然后拷贝到了一个没有中文字符的目录。


那我们现在继续把java编译的jar包,拷贝过去,路径是pmd-bin的lib下面,如下:


wKiom1kNOCvDdYcLAABwtIUeWj0320.png-wh_50



6. 利用自定义规则检测java代码


在pmd-bin目录打开命令行,执行


pmd.bat -d e:\work_space\Android-Prototype\app\src\main -f html -R java-mycustomrules


解释下参数:


-d: 表示你要检查的java源代码目录

-f: 表示输出的内容格式是html

-R: 表示要使用的规则,上面表示的是java里面的mycustomrules规则


wKiom1kNOVajz4x3AABKDdpd7Mg717.png-wh_50



其中hello pmd使我们打印的log: 

1
System.out.println("hello pmd");


上面检测到一个错误BaseActivity.java 78行有个while循环没有用{}


代码如下:


wKioL1kNOgOgmrA2AAALef4Dfns652.png-wh_50



七 用xpath语法自定义规则


这个可以参考帖子 xpath自定义规则


八 在AndroidStudio中配置PMD



  1. 增加配置模块

    可以新建一个module为config,在config module的quality.gradle里面配置pmd的task,如下:


  2. 1
    apply plugin: 'pmd'
  3. 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    check.dependsOn 'pmd'
     
    task pmd(type: Pmd) {
        ruleSetFiles = files("${project.rootDir}/config/quality/pmd/java/basic.xml", //基本代码规范
                "${project.rootDir}/config/quality/pmd/java/android.xml") //android相关
        ruleSets = []
        ignoreFailures = true
     
        source 'src'
        include '**/*.java'
        exclude '**/gen/**'
     
        reports {
            xml.enabled = true
            html.enabled = true
            xml {
                destination "${project.buildDir}/reports/pmd/pmd.xml"
            }
            html {
                destination "${project.buildDir}/reports/pmd/pmd.html"
            }
        }
    }


    简单描述下这几个属性:

    ruleSetFiles: 自定义的检测文件集合

    ruleSets=[]: 表示不用默认的检测xml,使用自定义的

    如果没有自定义规则,可以用系统的,那么ruleSets可以这样写:


    ruleSets = ["java-unusedcode", "java-basic"]

    中括号表示要检测的类型,不过这样有个缺点,如果我想去除java-basic里面一项检查,很难做到,不如自定义规则方便。


    ignoreFailures=true: 表示如果有错误,那么编译报错;如果是false,则只是输出错误报表,并不会中断编译。

    source:目录

    include: 包含文件

    exclude: 不包含的文件

    reports:输出报表的路径, xml.enabled表示是否输出xml。


  4. 在app的build.gradle增加对这个模块gradle的引用

  5. apply from: '../config/quality.gradle'

  6. 执行编译


  可以右击AndroidStudio的gradle里面pmd这个task(如果没有的话,可以build->rebuild project,在右边Gradle Projects里面刷新下)

  wKiom1kNRR3hvSUwAAA3wUw7Yn4202.png-wh_50



  或者在项目根目录,执行gradle pmd


    

7. 在Android Studio里面点击pmd和在命令行执行 gradle pmd的区别

  上面介绍了两种启动pmd检查的方法: Android Stdudio中点击pmd和命令行中兴gradle pmd

  我发现这种方法的检查结果不尽相同,经过仔细检查,终于发现了原因:


  所用的pmd版本不同


  a. Android Studio中点击pmd按钮执行的的pmd版本路径如下:

    File->Settings->搜索gradle,如下图:

    wKioL1kQNY_iBVx0AAB02AV9o5A840.png-wh_50


  那我的Android Studio编译pmd使用的pmd路径就是 D:/gradle_jar_cache

  这个路径是我自己配置的。

 

  如果这个路径下没有pmd,那么它会去下载,下载的路径在项目下面的build.gradle中配置,也即是maven服务器地址。

  

1
2
3
4
5
6
7
8
9
10
11
allprojects {
    repositories {
//        jcenter()
        maven {
            url '   
        }
         
 
        mavenCentral()
    }
}

  


   b. 命令行执行gradle pmd

   

   说下这种方法的pmd路径,因为自己在Gradle里面找了好久也没有找到,后面突然想到了默认路径,也就是"c:\Users\rongwei.huang\.gradle\"

   自己就把这个文件夹备份后删除,再在命令行执行gradle pmd,果然它首先就去进行了下载jar包操作。

   在这个目录搜索pmd,发现它的版本是5.2.3与Android Studio里面用的5.5.4不一样,所以两者会有不同的检查结果。


   因为我的是UnusedPrivateMethod 检查不同,也就是没有被使用的私有方法检查,5.2.3会误报;所以我对比了下源代码。

   5.2.3的源代码没有找到,拿5.0版本和5.5.4版本对比,发现它们的实现不一样:


wKioL1kQSciycJTOAASs_oyxWIA278.bmp



   

wKiom1kQSYTh5aa2AASfrYhaHJ8252.bmp  

   


   


   









c. 疑问

   1. Gradle在哪里配置pmd版本的呢?比如我的会自动下载5.2.3,那这个是在哪里配置的呢?

   2. Gradle是在哪里配置默认pmd路径的呢?也就是"c:\Users\rongwei.huang\.gradle\"

   这两点没有找到。

   如果有找到的同学,可以留言告诉我,谢谢~


````分割线````

已经找到了Gradle为什么会下载到c:\Users\rongwei.huang\.gradle\, 这个是当前用户根目录。

如果要修改的话,可以添加环境变量“GRADLE_USER_HOME”,为它设置一个目录即可。


详见gradle-wrapper.properties


1
2
3
4
5
6
#Mon Sep 12 15:17:35 CEST 2016
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-3.1-rc-1-bin.zip




附录:

下面是pmd的一些相关网址

  1.  PMD github源代码  下载时注意branch

  2.  PMD介绍 包括大部分PMD检查分类的介绍,比如basic是干什么

  3.  PMD自定义规则的实现

  4.  PMD官网

  5.  安装maven

  6.  PMD java doc编译失败


谢谢上面的博主。





     本文转自rongwei84n 51CTO博客,原文链接:http://blog.51cto.com/483181/1922605,如需转载请自行联系原作者


网友评论

登录后评论
0/500
评论
技术小胖子
+ 关注