拡張アリのP3Cチェックするカスタムコード規格を実装

 いくつかの時間前に欠陥、ちょうどオープンsetAutoType特性危険性があることを報告fastjson、自分のテスト環境のプロジェクトが引き出されました-_-!。変化が小さいですが、ちょうど立ち往生感じています。これが無効になって残念です、とお金のツールヒントを見つけるfastjson使用している場合、この機能を開けないと思いますし、言葉で安全に注意を払う考え、fastjsonかなり良いです。アリはちょうどP3C(開くhttps://github.com/alibaba/p3cルールを設定することができ、対応するプラグインのIDEは、符号化プロセス中にプロンプトが表示された)、標準化されたコードの検査ツールが、あり、我々はそれを行うつもり拡大、オープン検査setAutoType特性のためfastjsonチェックを高めます。

 P3Cは、主に3つの部分が含まれています。

  • 使用PMD:PMDは(P3C-PMD)を達成しhttps://pmd.github.io/コードの仕様チェックを達成します
  • IntelliJ IDEAプラグイン
  • Eclipseのプラグイン

 「アリ・ババのJava開発マニュアル」には、ルールのほとんどは、この部分はまた、研究のこのセクションの主要な部分である、実装P3C-pmdをモジュールです。

1. PMD

 P3Cは、PMDを使用しています。PMDはJavaコードブロックは、それが不要なオブジェクトが含まれているかどうか、空のグリッパーを有しているか否か、未使用の変数を含んでいるかどうかを確認するために行うことができる静的コードスキャンツールです。PMDは、ソースコードを解析するJavaCCのパーサーを使用して生成され、AST(抽象構文木)を生成PMD内のルールと呼ばれる、ソースコード、テキストコードから直接ASTレベルの検査によって確認することができます。それはその後、ASTに表示される確認し、ルールが可能文言を徹底的にソースを参照するかどうか、です。実装のための規則は、焦点は、ASTの取り扱いになります。

1.1。AST

 ASTの導入について、あなたが直接検索することができ、オンラインの多くがありますが、ここでは2つのことが重要です。

  • ASTは、ソースコードの抽象構文木構造で表現したものです
  • 抽象構文木は、分析フェーズで使用したのと同じ構文のコンテキストが独立していること、オリジナルの言語の構文に依存しません

 PMDは、JavaCCのASTを使用して生成されます。JavaCCのについてあなたもどこ少し紹介、インターネット上の情報を表示することができ、ちょうどJavaCCのは、字句解析ジェネレータとパーサジェネレータは、罰金になります知っています。

1.2。カスタムルール

 PMDの公式文書は、カスタムルールを達成するための手順を説明し、プロセスが比較的明確である、この記事の下に、ここではそれらを繰り返すだけではなく、デザインを必要な手順を説明します。

1.2.1。ルールのセットを定義

 PMDのルールは、XMLファイルで設定する必要があります

  • 次の空のファイル表現のルールセットを作成します。
    <?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>
    ```
    
* 在上面的``` ruleset ``` 标签中引用自定义规则

    ```
    <rule ref="pathToYourOwnClass" />
    ```

* 配置规则集 
    
###### 1.2.2. 配置规则

&emsp;可以在 ``` rule ``` 标签中对某一规则进行配置

* 配置提示消息和告警级别

    ```
    <rule ref="pathToYourOwnClass"
      message="message to show" >
      <priority>5</priority>
    </rule>
    ```
    告警优先级分为1-5个level,1最高,5最低
    
* 配置运行参数

    可以通过 ``` properties ``` 和 ``` propertie ```对类属性赋值
    
###### 1.2.3. 编写规则

&emsp;规则的编写比较简单,PMD已经给我们做好了配套的开发框架和工具,只要确定后规则出现的情况,按照固定的模式去编写即可。

* 确定实现方式

    可以使用纯Java方式实现,也可以使用XPath方式实现。
    
    对于纯Java方式,PMD框架本身实现了对AST数的遍历,用户只要在遍历各个节点的时候,对自定义规则的各种情况进行分析判断即可,过程类似与DOM文件的SAX解析,以流和事件的方式来解析AST内容。
    
    对于XPath方式,则是将AST作为一个XML数,以XPath的方式来遍历解析内容。
    
* 根据测试代码确定可能出现的情况

    PMD自带了一个designer,可以用来生成对应代码的AST内容。对于本文需要达到的效果,涉及到如下代码:
    
    ```
    
    import com.alibaba.fastjson.parser.ParserConfig;

    public class NegativeExample {
    
        public static void main(String[] args) {
            ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
        }
    }
    
    ```
    
    在designer中可以得到如下的AST内容
    
  ![file](https://img2018.cnblogs.com/blog/1812801/201910/1812801-20191025160959878-590799600.jpg)
    
    具体内容这里就不贴出来了,可以下载desigin然后贴上上面的代码就会有。
    
    对于本文的需求,需要确定在有import ``` ParserConfig ``` 类的时候,调用了 ``` setAutoTypeSupport ``` 方法且参数为 ``` true ```。当然这个条件是不够严谨的,还需要判断是否调用了 ``` ParserConfig ```,也要考虑有通过import导入直接写全限定名的。但考虑到一般的写法,以及ide的格式化处理,这样处理已经可以满足大部分场景了。
    
* 编写规则实现类

    确定了规则的判断条件,就可以着手写代码了。
    
    对于Java方式,可以直接继承 ```net.sourceforge.pmd.lang.java.rule.AbstractJavaRule ``` 类,然后重写各种节点的visit方法即可。
    
    例如如下,用于判断是否有import ``` ParserConfig ``` 类
    
    ```
    private final String PARSER_CONFIG_IMPORT_NAME = "com.alibaba.fastjson.parser.ParserConfig";
    
    private boolean hasImport = false;
    
    @Override
    public Object visit(ASTImportDeclaration node, Object data) {
        if (PARSER_CONFIG_IMPORT_NAME.equals(node.getImportedName())) {
            hasImport = true;
        }
        return super.visit(node, data);
    }
    ```

    对于XPath方式,可以通过继承 ``` net.sourceforge.pmd.lang.rule.XPathRule ``` 类,重写 ``` setXPath ``` 方法设定对应的XPath即可。上面提到过,可以通过 ``` property ``` 配置对类的属性进行赋值,因而,对于XPat方式,可以在xml配置中进行如下设置来启用XPath。
    
    ```
    <rule name="My Rule"
          language="java"
          message="violation message"
          class="net.sourceforge.pmd.lang.rule.XPathRule">
        <description>
Rule Description
         </description>
         <priority>3</priority>
         <properties>
             <property name="xpath">
                 <value>
                 <![CDATA[
--- here comes your XPath expression
]]>
                 </value>
             </property>
         </properties>
    ```

###### 1.2.4. 测试规则

&emsp;PMD推荐对于每个规则,至少要有一个正向和逆向的测试用例,来验证规则出现和不出现的情况。对于规则的测试,PMD也提供了一套框架,只要按照约定好的方式添加xml测试文件即可。

&emsp;PMD约定了几个规则,用来加载测试案例

* 测试类要继承 ``` net.sourceforge.pmd.testframework.PmdRuleTst ```类,该整合了Junt,可以在里面增加需要的测试方法。

* 对于在 ``` src/test/resource ``` 和测试类对应的路径下增加一个xml目录,在增加同第一步同名的xml文件,该文件用于书写测试集。

    例如官网给出的例子

    规则实现类路径如下:

    ```
net.sourceforge.pmd.lang.java.rule.bestpractices.AbstractClassWithoutAbstractMethodTest
        
    ```
    
    测试案例集如下:
    
    ```
    src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/AbstractClassWithoutAbstractMethod.xml
    
    ```
    
    xml的规则则可以参考官网介绍,这里不再赘述。

#### 2. p3c-pmd

&emsp;代码规范实现的主要模块,使用pmd来实现。p3c-pmd模块在代码组织上很工整,可以按照相同的模式增加自定义的规则/规则集。

&emsp;对于本文需求,打算在该模块的基础上增加一个extend模块,用于实现自定义规则集。如下,为对应的源码路径好规则集路径

![file](https://img2018.cnblogs.com/blog/1812801/201910/1812801-20191025161000108-1340099359.jpg)

![file](https://img2018.cnblogs.com/blog/1812801/201910/1812801-20191025161000368-199680801.jpg)

&emsp;本文采用纯Java方式实现规则,按照1.2.3.节的描述,可以得到如下的实现类

パブリッククラスAvoidFastJsonAutoTypeSupportRuleはAbstractAliRuleを{延び

private final String PARSER_CONFIG_IMPORT_NAME = "com.alibaba.fastjson.parser.ParserConfig";

private final String SET_AUTO_TYPE_SUPPORT_NAME = "setAutoTypeSupport";

private boolean hasImport = false;


@Override
public Object visit(ASTImportDeclaration node, Object data) {
    if (PARSER_CONFIG_IMPORT_NAME.equals(node.getImportedName())) {
        hasImport = true;
    }
    return super.visit(node, data);
}

@Override
public Object visit(ASTPrimaryExpression node, Object data) {
    if (hasImport) {
        int size = node.jjtGetNumChildren();
        for (int i = 0; i < size; i++) {
            Node child = node.jjtGetChild(i);
            String imageName = null;
            if (child instanceof ASTPrimaryPrefix) {
                ASTPrimaryPrefix prefix = (ASTPrimaryPrefix) child;
                imageName = prefix.jjtGetChild(0).getImage();
            }else if (child instanceof ASTPrimarySuffix){
                ASTPrimarySuffix suffix = (ASTPrimarySuffix) child;
                imageName = suffix.getImage();
            }

            if (imageName == null) {
                continue;
            }else if (imageName.endsWith(SET_AUTO_TYPE_SUPPORT_NAME)){
                ASTPrimarySuffix argumentSuffix = (ASTPrimarySuffix) node.jjtGetChild(i + 1);
                try {
                    List<Node> booleanArgs = argumentSuffix.findChildNodesWithXPath("//PrimaryPrefix/Literal/BooleanLiteral");
                    if (booleanArgs.size() == 1) {
                        ASTBooleanLiteral booleanLiteral = (ASTBooleanLiteral) booleanArgs.get(0);
                        if (booleanLiteral.isTrue()) {
                            ViolationUtils.addViolationWithPrecisePosition(this, argumentSuffix, data,
                                I18nResources.getMessage("java.extend.AvoidFastJsonAutoTypeSupportRule.rule.msg" ));
                        }
                    }
                } catch (JaxenException e) {
                    e.printStackTrace();
                } finally {
                    break;
                }
            }
        }
    }
    return super.visit(node, data);
}

}


&emsp;对应规则集中的配置为
Javaの .extend.AvoidFastJsonAutoTypeSupportRule.rule.desc 1つの悪い例:インポートcom.alibaba.fastjson.parser.ParserConfig。
  public class NegativeExample {

      public static void main(String[] args) {
          ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
      }
  }

]]>


&emsp;这里有几点需要注意的,类 ``` AvoidFastJsonAutoTypeSupportRule ``` 继承自 ``` com.alibaba.p3c.pmd.lang.java.rule.AbstractAliRule ```,AbstractAliRule继承自AbstractJavaRule,重写了setDescription,setMessage和addViolationWithMessage等方法,这里提到的3个方法,增加了多语言支持。p3c-pmd使用Resource Bundle来提供多语言支持。每个消息都有一个唯一id来对应,p3c-pmd通过重写方法,将方法参数映射为消息的id,以统一消息的配置。如下为本地对应的消息提示内容
<!--extend-->
<entry key="java.extend.AvoidFastJsonAutoTypeSupportRule.rule.msg">
    <![CDATA[不要打开fastjson的setAutoTypeSupport特性]]>
</entry>
<entry key="java.extend.AvoidFastJsonAutoTypeSupportRule.rule.desc">
    <![CDATA[

説明:特性はセキュリティ上の脆弱性をfastjson setAutoTypeSupport
]]>


&emsp;对于测试,按照1.2.4.的介绍,则有如下的文件路径

![file](https://img2018.cnblogs.com/blog/1812801/201910/1812801-20191025161000622-547325296.jpg)

文件内容比较简单,这里就不贴出来了。

&emsp;至此,已经完成了自定义规则的实现,现在就是要把该内容应用到ide上了。首先,需要将该模块进行编译,这里直接保存到本地maven参考,好在本地调试。

&emsp;直接将p3c-pmd的版本升级为2.0.1,然后执行mvn install,可以在本地仓库看到对应的版本

![file](https://img2018.cnblogs.com/blog/1812801/201910/1812801-20191025161000982-1139222394.jpg)

有了该版本,则可以在其他模块引用该版本进行新功能调试,下面将以idea-plugin模块为例。

#### 3. idea-plugin

&emsp;idea-plugin主要实现了idea的插件,能够对代码进行实时检查。这里涉及到idea自定义插件的开发,这里就不深入了,网上有很多教程。这里只介绍如何将上面自定义的规则接入该模块。

1.修改idea-plugin模块的build.gradle文件,开启本地仓库配置,以便从本地直接加载最新的p3c-pmd依赖。

buildscript {
リポジトリ{
達人{
URL "https://oss.sonatype.org/content/repositories/snapshots/"
}
達人{
URL 'http://dl.bintray.com/jetbrains/intellij-plugin-service'
}
mavenLocal ()
mavenCentral()

}
dependencies {
    classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}

}

allprojects {
グループ「com.alibaba.p3c.ideaは、」
プラグインを適用する:「Javaの
プラグインを適用する:「kotlinは、」
プラグインを適用する:「mavenのパブリッシュ」

sourceCompatibility = 1.8
compileJava.options.encoding = 'UTF-8'
configurations.all {
    resolutionStrategy.cacheChangingModulesFor 0, 'seconds'
}
repositories {
    mavenLocal()
    jcenter()
    mavenCentral()
}

dependencies {
    compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
    testCompile group: 'junit', name: 'junit', version: '4.11'
}

}


如上,增加了```mavenLocal()```

2.修改p3c-common的build.gradle,更改p3c-pmd的版本为2.0.1

3.修改p3c-common模块resources/rulesets/java/ali=pmd.xml,增加


`` `

カスタムルールのチェックを追加します。

P3C、共通モジュール4.実行gradle clean buildPlugin対応するプラグインを生成します、。

4.確認してください

 ローカルでプラグインをインストールし、次のような効果を得ることができます

 ここだけfastjsonの導入に実際に依存しない、効果を検証するために、また、PMDのチェックがソーステキストで確認しました。

おすすめ

転載: www.cnblogs.com/jwcz/p/11738868.html