zoukankan      html  css  js  c++  java
  • Sonar Java 规则插件开发 (基于阿里开发手册)

    引言

    最近在做Sonar静态代码扫描管理,以此顺手接了Sonar的插件开发,基于阿里开发手册进行开发,在整体开发过程中,其中还是遇到不少坑位,也以此给大家做相应借鉴
    官网Demo演示插件开发地址:
    https://docs.sonarqube.org/display/PLUG/Writing+Custom+Java+Rules+101
    基于官网的我暂时不多说,基础框架按照官网的范例进行搭建即可

    #开源地址:
    https://github.com/tigerge000/sonar-java-custom-rules.git

    sonar常用方法说明

    范例

    需求:【强制】抽象类命名使用 Abstract 或 Base 开头;异常类命名使用 Exception 结尾;测试类 命名以它要测试的类的名称开始,以 Test 结尾。
    实现:
    AbstractClassNameCheck

    package org.finger.java.rule.checks.namerules;

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.sonar.check.Rule;
    import org.sonar.plugins.java.api.JavaFileScanner;
    import org.sonar.plugins.java.api.JavaFileScannerContext;
    import org.sonar.plugins.java.api.tree.*;

    /**
    * 抽象类命名检查
    * 抽象类命名使用 Abstract 或 Base 开头
    * Created by 古月随笔 on 2017/3/17.
    */
    @Rule(key = "AbstractClassNameCheck")
    public class AbstractClassNameCheck extends BaseTreeVisitor implements JavaFileScanner{

    private static final Logger LOGGER = LoggerFactory.getLogger(AbstractClassNameCheck.class);

    private JavaFileScannerContext context;

    @Override
    public void scanFile(JavaFileScannerContext context) {
    this.context = context;
    scan(context.getTree());
    }

    @Override
    public void visitClass(ClassTree tree) {
    String className = tree.simpleName().name();

    LOGGER.info(className + "<<>>" + tree.symbol().isAbstract());


    if(tree.symbol().isAbstract()){
    //判断名称是否以Abstract 或 Base 开头

    String abName = "Abstract";
    String bsName = "Base";
    //判断类名如果小于Abstract 或 Base
    if (className.length() < abName.length() || className.length() < bsName.length()) {
    context.reportIssue(this, tree, "The Name Of Abstract Class should use Abstract or Base first");
    } else {
    //判断是否存在 Abstract 或 Base
    if (!className.contains(abName)) {
    if (!className.contains(bsName)) {
    context.reportIssue(this, tree, "The Name Of Abstract Class should use Abstract or Base first");
    } else {
    if (className.indexOf(bsName) != 0) {
    context.reportIssue(this, tree, "The Name Of Abstract Class should use Abstract or Base first");
    }
    }
    } else {
    if (className.indexOf(abName) != 0) {
    context.reportIssue(this, tree, "The Name Of Abstract Class should use Abstract or Base first");
    }
    }
    }
    }
    super.visitClass(tree);
    }

    }

    resources目录下添加目录:org.sonar.l10n.java.rules.squid(这命名主要是由于sonar源码中固定写死的)
    AbstractClassNameCheck.html

    <p>AbstractClassNameCheck Check</p>
    <h2>Noncompliant Code Example</h2>
    <pre>
    public abstract class HiClass {// Noncompliant
    }

    public abstract class MyNameIsAbstract {// Noncompliant
    }
    </pre>
    <h2>Compliant Solution</h2>
    <pre>
    public abstract class AbstractMysql {
    }

    public abstract class BaseMysql {
    }
    </pre>

    AbstractClassNameCheck.json

    {
    "title": "The Name Of Abstract Class should use Abstract or Base first",
    "status": "ready",
    "remediation": {
    "func": "Constant/Issue",
    "constantCost": "5min"
    },
    "tags": [
    "bug",
    "pitfall"
    ],
    "defaultSeverity": "CRITICAL"
    }

    AbstractClassNameCheck_java.json(为什么有这个文件,主要是由于进行单测的时候,sonar源码内容写死是xxxx_java.json命名)

    {
    "title": "The Name Of Abstract Class should use Abstract or Base first",
    "status": "ready",
    "remediation": {
    "func": "Constant/Issue",
    "constantCost": "5min"
    },
    "tags": [
    "bug",
    "pitfall"
    ],
    "defaultSeverity": "CRITICAL"
    }

    单测:
    AbstractClassNameCheckTest

    package org.finger.java.rule.checks.namerules;

    import org.junit.Test;
    import org.sonar.java.checks.verifier.JavaCheckVerifier;

    /**
    * Created by huqingen on 2017/3/17.
    */
    public class AbstractClassNameCheckTest {
    @Test
    public void test() {
    JavaCheckVerifier.verify("src/test/files/HiClass.java", new AbstractClassNameCheck());
    }

    @Test
    public void test1() {
    JavaCheckVerifier.verify("src/test/files/MyNameIsAbstract.java", new AbstractClassNameCheck());
    }

    @Test
    public void test2() {
    JavaCheckVerifier.verify("src/test/files/BaseMysql.java", new AbstractClassNameCheck());
    }
    @Test
    public void test3() {
    JavaCheckVerifier.verify("src/test/files/AbstractMysql.java", new AbstractClassNameCheck());
    }
    }

    开发目录结构:

     

    PS:
    1.编写sonar规则的时候,给个建议,采用Debug方式调试整个tree里面的内容,针对性的编写自己想要的规则,sonar在这块扫描基础方法做的还是很棒的

  • 相关阅读:
    ffmpeg命令行获取RTSP流并每秒截取一张解码存储为jpg
    快速排序
    ffmpeg参数中文详细解释
    Docker
    elasticsearch的安装和配置
    C 语言-运算符(算术运算符,类型转换,赋值运算符,自增,自减,sizeof 运算符,逗号运算符,关系运算符,逻辑运算符,三目运算符)
    c语言-printf函数和scanf函数简单使用
    将JPA通用的实现方法封装成一个抽象类进行拓展
    工具类里的静态变量如何获取application.yml或者application.properties里的属性
    记java实体类属性名为全部为大写踩的坑(基础)
  • 原文地址:https://www.cnblogs.com/feihufeihu/p/10676304.html
Copyright © 2011-2022 走看看