【千奇百怪】java自定义spotbugs检测器

标签: 千奇百怪  java  开发语言  intellij-idea

两天,在对一个代码质量检测平台维护的时候,遇到了一个新添加指定规则集的需求,在经过一番折腾后否定掉了基于 ANTLR 实现自定义规则;基于 CheckStyle 实现自定义规则;基于 PMD 实现自定义。最后确定前几个静态扫描工具完成不了这个任务,调研后找到了基于findbugs的class文件扫描工具-- spotbugs

系列文章目录

【java自定义spotbugs检测器】
【PHP代码质检工具PHPCS分析介绍与使用】



一、什么是SpotBugs

SpotBugs是Findbugs的继任者(Findbugs已经不再维护),用于对Java代码进行静态分析,查找相关的漏洞,SpotBugs比Findbugs拥有更多的校验规则。静态分析会检查Java字节码(.class文件)是否存在错误模式(错误模式是一种经常容易出错的代码表达式/习惯用法,其中主要包括:错误使用编程语言的某些特性、误用的API方法、在维护期间修改代码时误解变量、错别字,使用错误的运算符)注: SpotBugs 需要当前的JDK环境为 1.8以上,但可以对1.0~1.9的代码来进行检查。SpotBugs是对.class文件进行扫描的,所以工程必须成功完成编译并生成.class文件。可以通过如下方式使用Spotbugs:

? Ant

? Maven

? Gradle

? Eclipse

SpotBugs是可扩展的,可以通过插件添加新的检测器

二、自定义规则

1.安装
前往下载https://github.com/spotbugs/spotbugs/releases/tag/4.7.1
本地解压即可使用,更详细的配置可以根据官方文档进行。
2.解压后spotbugs-4.7.1/bin/spotbugs 即为启动命令
3.确认maven与jdk完善后,使用maven命令创建自定义检测器项目

mvn archetype:generate \
      -DarchetypeArtifactId=spotbugs-archetype \
      -DarchetypeGroupId=com.github.spotbugs \
      -DarchetypeVersion=0.2.3

注意,这里与官方不一样的地方在于version,官方文档的0.2.4有一些问题,会无法完整创建。
在这里插入图片描述
成功使用命令后会让你依次输入你的项目的groupid,artifacid,version,package。

DgourpId: 组织名,公司网址的反写 + 项目名称
DartifactId: 项目名-模块名
DarchetypeArtifactId: 指定 ArchetypeId,maven-archetype-quickstart,创建一个简单的 Java 应用

4.创建完成使用idea打开项目,加载完成是下图这样的目录结构
在这里插入图片描述
可能缺少findbugsplugin与messagecollection两个.xsd文件,打开官方的源码搬一份
5.安装jaclass插件
spotbugs是对class文件进行处理,这其中涉及到java的字节码与助记符,详细知识点可以自行百度。这里可以简单理解为,java文件编译为二进制文件后,通过助记符可以将其每一个编译命令展示出来,也就可以追溯到每一个方法每一个类,因此我们可以根据字节码去校验规则。
在这里插入图片描述
安装完成后,在测试文件中写出需要检测出的错误类别和正确类别,在view中找到jclass…选项

在这里插入图片描述
点击之后就会在右侧栏出现下图页面,关于更详细的使用点击这里或者自行搜索,我们只需要知道,在方法下的main中的code就是我们的主要内容
在这里插入图片描述
通过分析可以找到例子的目标函数,future函数,正确与错误是看get调用时是否有延时参数,两处调用很明显是没有参数时缺少JLjava/util/concurrent/TimeUnit;
在这里插入图片描述

5.根据需求编写规则检测
根据观测结果我们就可以编写相应的规则

import org.apache.bcel.Const;

import edu.umd.cs.findbugs.BugInstance;
import edu.umd.cs.findbugs.BugReporter;
import edu.umd.cs.findbugs.bcel.OpcodeStackDetector;

public class MyDetector extends OpcodeStackDetector {
    private final BugReporter bugReporter;

    public MyDetector(BugReporter bugReporter) {
        this.bugReporter = bugReporter;
    }

    @Override
    public void sawOpcode( int seen) {
        //检测调用指令,future调用处的指令
        if (seen == Const.INVOKEINTERFACE) {
            //getNameConstantOperand 方法获取被调用方法的名称 ,getClassConstantOperand获取调用类名称的方法
            //检测调用对象以及方法
            if ("java/util/concurrent/Future".equals(getClassConstantOperand())
                    && ("get".equals(getNameConstantOperand()))) {
                //getSigConstantOperand 方法的意思是获取方法的所有参数
                if ( !this.getSigConstantOperand().equals("(JLjava/util/concurrent/TimeUnit;)Ljava/lang/Object;")
                ) {
                    bugReporter.reportBug(new BugInstance(this, "JAVA_FUTURE_CALL_TYPE", HIGH_PRIORITY)
                            .addClassAndMethod(this).addSourceLine(this));
                }
                }
        }

        }
}

该类的实现是继承 OpcodeStackDetector 类,是 FindBugs 中的一个抽象类,封装了方法调用来获取代码具体参数 .sawOpcode 方法参数可以理解为要检测的代码行的行号,采用 printOpCode(seen)可以打印这行代码的详细信息 .Constants.INVOKEVIRTUAL 表示该行调用了类的实例方法 ,Constants.INVOKESTATIC 表示调用类的静态方法 .getNameConstantOperand 方法获取被调用方法的名称 ,getClassConstantOperand获取调用类名称的方法,getSigConstantOperand 方法的意思是获取方法的所有参数 .bugReporter.reportBug 用来上报检测到的漏洞信息,其中BugInstance的三个参数分别代表:detector、Hole type、Vulnerability level,漏洞级别分为五个级别,如下表所示:

name Parameters meaning
HIGH_PRIORITY 1 High risk
NORMAL_PRIORITY 2 Medium risk
LOW_PRIORITY 3 Low risk
EXP_PRIORITY 4 Safety alert
IGNORE_PRIORITY 5 Negligible risk

addClass、addMethod、addSourceLine 用于指定漏洞所在的类、方法、即可,便于在报告漏洞时定位关键代码。

6.更新 findbugs.xml
SpotBugs 读取findbugs.xml每个插件以查找检测器和错误。因此,当添加新检测器时,需要添加新元素,如下所示:

<Detector class="com.github.plugin.MyDetector" reports="MY_BUG" speed="fast" />

还需要添加, 来描述错误模式的类型和类别。

<BugPattern type="MY_BUG" category="CORRECTNESS" />

可以findbugs.xml在src/main/resources生成的 Maven 项目的目录中找到。

7.更新messages.xml
SpotBugs 读取messages.xml每个插件以构建人可读的消息以报告检测到的错误。它还支持读取本地化消息messages_ja.xml,messages_fr.xml等等。

可以messages.xml在src/main/resources生成的 Maven 项目的目录中找到。

检测器更新信息
在元素中,可以添加检测器的描述消息。请注意,它应该是纯文本,不支持 HTML。

<Detector class="com.github.plugin.MyDetector">
  <Details>
    Original detector to detect MY_BUG bug pattern.
  </Details>
</Detector>

因为我不是搞java的使用没有很多能解释的地方,有需求的同学自己查找资料,会java的应该都能比我写的更好。

详细参数文档:https://spotbugs.readthedocs.io/en/latest/running.html
插件定义文档:
https://spotbugs.readthedocs.io/en/latest/implement-plugin.html

三、校验并使用

我们在编写好文件后,使用maven将自定义规则打包成jar包,并在测试文件处使用检测效果。
1、首先idea下载插件spotbugs在这里插入图片描述
安装后在tools里找到它,点击plugins处的+号,选择4并将我们导出的jar文件添加。在这里插入图片描述
然后右键使用即可
在这里插入图片描述
当发现我们自定义的规则能够满足需要,在检测中可以起到作用,我们就可以使用了
在这里插入图片描述
我们下载的spots源码支持
命令行 或者专有的 GUI 工具运行
Eclipse 插件
Maven、Gradle 插件
SonarQube 插件
等方式运行。

将我们自定义的插件放入源码的plugin文件夹下就会默认启用

/Users/Downloads/spotbugs-4.5.0/bin/spotbugs -textui -xml:withMessages=out.xml -quiet -include filter.xml /Users/JAVA/pmd_dir/test/out/production/test

所使用的参数的含义分别是:
-textui 在命令行执行(否则SpotBugs会以GUI的方式运行)
-low 返回所有问题(默认是只返回等级为medium和high的问题)
-xml:withMessages=out.xml 结果输出格式为xml,输出到到当前目录的out.xml中,并且附加上问题的描述信息
-include filter.xml 只报告满足filter.xml中限制的问题
Users/JAVA/pmd_dir/test/out/production/test 为要扫描的代码库目录

其中,filter的详细配置可见此链接,为了可以灵活执行要扫描的规则,我们的使用方法为

<?xml version="1.0" encoding="UTF-8"?>
  <FindBugsFilter
            
  <Match>
    <Bug pattern="DMI_HARDCODED_ABSOLUTE_FILENAME" />
  </Match>
 
  <Match>
    <Bug pattern="NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE" />
  </Match>
 
 
</FindBugsFilter>

在以上filter.xml的例子中,每个Match代表一条规则/问题

版权声明:本文为qq_45725675原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_45725675/article/details/126363665

智能推荐

新发的日常小实验——使用IETester测试不同IE版本的浏览器,测试网页JS的兼容性(console未定义兼容测试)

文章目录 一、痛点:IE兼容测试 二、关于IETester 三、IETester下载 四、写个html测试js的console接口 五、测试结果 六、js兼容处理 一、痛点:IE兼容测试 之前使用.Net的Winform桌面应用框架做了一个PC版的迷你浏览器(使用IE内核),方便拉起网页支付。 有用户反馈打开支付页面报了如下的错:“console”未定义 到底是多么老旧的I...

linux下搭建nginx及配置

文章目录 下载nginx 解压nginx资源包 准备编译环境 安装编译 查找安装路径并启动nginx 浏览器访问 下载nginx 下载地址:https://nginx.org/en/download.html 这里用的是nginx-1.16.1版本 解压nginx资源包 准备编译环境 安装编译 查找安装路径并启动nginx 浏览器访问 http://IP...

腾讯云+tipask快速搭建基于laravel的CMS网站

一、购买腾讯云服务器,服务市场->基础环境->选择WordPress平台镜像 二、按照tipask教程安装 tipask官方教程地址https://wenda.tipask.com/article/22 官方教程对新手不太友好,我整理如下: 1.ftp上传文件 云服务器镜像装载完毕后,浏览器访问服务器公网ip,点击获取权限后会下载服务器相关的文件 浏览器访问host url,根据所给的...

ElasticSearch入门教程

什么是ElasticSearch 基于Apache Lucene构建的开源搜索引擎 采用Java编写,提供简单易用的RESTFul API 轻松的横向扩展,可支持BP级的结构化和非结构化的数据处理 可应用场景 海量数据分析引擎 站内搜索引擎 数据仓库 一线公司实际应用场景 英国卫报 - 实时分析公众对文章的回应 维基百科、GitHub-站内实时搜索 百度 - 实时日志监控平台 安装 Windows...

小程序明明已经分包了,为啥没有大小没有变???

为什么要分包 真机预览时出现大于2M,无法预览。 对项目进行规整划分 如何分包 实际操作 先将需要分包的文件拷贝到小程序根目录下 在app.json中配置分包结构(如图) 修改被分包中的引用路径,如图片资源、导航URL 可以设置分包的在哪个页面加载 图中表示在进入login页面进行下载设置的分包,all表示在所有网络下。 失败解决!分包了为啥还是提示大小超过2M 分包的文件内所引用的外部文件也必须...

猜你喜欢

js pixi框架 极其详细到位(入门)-----转载

pixi是一个js 的轻量级的游戏类库框架,很适用于做H5的一些canvas动画特效。 这篇文章是关于pixi的入门教程 ,里面的讲解非常的到位细致,是我看到过的文章里讲解的算是最好的了。  去年快过年看的教程 ,今天再想看的时候发现没找到,不过经过不懈的搜索还是找到 ,那就赶紧给转过来吧。   pixi(入门) Pixi教程 基于官方教程翻译;水平有限,如有错误欢迎提PR,转...

sklearn支持向量机(SVM)多分类问题

模型 sklearn.svm中的支持向量机: Classify:SVC、nuSVC、LinearSVC Regression:SVR、nuSVR、LinearSVR OneClassSVM 本文采用Classify系列,classify三个模型的区别;参数详解 预处理 建模 训练 多种SVC、核函数对比 对比的结果: 优化linear核函数的SVC的惩罚系数 惩罚系数(C=)越高,对错误分类的惩罚...

第一阶段:CSS初步探讨

传统盒子和怪异盒子的初接触 作为一个小白,第一次碰到这种盒子,总算能对盒子变形有一点粗浅认识了,不多说,直接上代码观察 传统盒子的宽高等于内容区域的宽高,如果padding改变则会导致整个盒子变形,撑开来,如box1和box1-1所示 怪异盒子的宽高=内容的宽高+padding2+border2,所以改变padding时不会改变整个盒子的大小,不会变形...

Etherlab源码解析--ecdev_offer()

在linux系统中,网卡及对应的net_device结构体实例是由上层的网络子系统操作的,ecdev_offer()的作用是将网卡转交给ehterlab master操作。 一、预备知识net_device结构体 linux系统中,每一个网卡对应一个net_device结构体的实例,一个网卡要能够被内核识别并收发数据,一般需要经过net_device结构体的创建、初始化、注册到内核、打开设备等步骤...

ARM裸机的知识点总结---------10、解决X210开发板软开关按键问题( 引脚功能复用)

Author: 想文艺一点的程序员 自动化专业 工科男 再坚持一点,再自律一点 CSDN@想文艺一点的程序员 来自朱有鹏嵌入式的学习笔记 目录 1、X210开发板的软启动电路详解 2、为什么要软启动 3、开发板供电置锁原理和分析 4、写代码+实验验证 1、X210开发板的软启动电路详解 (1)210供电需要的电压比较稳定,而外部适配器的输出电压不一定那么稳定,因此板载了一个文稳压器件MP1482....


http://www.vxiaotou.com