详解eclipse插件findbugs新规则的开发过程

news/2024/7/4 0:52:12 标签: eclipse插件, class, eclipse, import, build, library
class="baidu_pl">
class="article_content clearfix">
class="htmledit_views">

java应用最常见的也就是NullPointException问题。平时做小的项目出几个NPE没什么太大的影响,打几个错误日志,下次修复掉就行了。但是如果是淘宝、支付宝这样的大型系统,每天用户量很大,可能一个NPE就会影响到很多用户的系统使用。findbugs会容易的找出这些问题。
有的时候findbugs不能满足需求,需要在代码扫描阶段就发现更多的问题,那么就需要开发针对需求的findbugs规则。比如:生产环境的代码中是不允许有System.out.prinln("xxxxx");这样的信息出现的,必须使用log来记录日志,所以我们就可以专门写一条规则来检测代码里面是否存在System.out,如果存在就给出提示。
同样的,在使用log日志的时候,必须要先判断日志的级别然后再使用log.debug(""),所以我们可以定义一条日志来检测代码中是否存在没有使用if条件判断就直接log.debug(),有的话给出提示。
通过找代码中是否存在System.out来讲解findbugs规则的开发过程
效果:

准备class="t_tag">工作
1 findbugs源码的class="t_tag">下载class="t_tag">下载路径:
http://code.google.com/p/findbugs/source/checkout 通过svn下载,svn命令: Svn checkout http://findbugs.googlecode.com/svn/trunk/ findbugs-read-only
2 将源码导入eclipse
eclipse中选择import --- plug-ins and fragments,选择下载的findbugs源码的路径import as选项卡中选择 projects with source folders
添加plug-ins的时候记得不要选择中间的那个,中间的是test,也可以选择全导入
3 项目环境设置
在edu.umd.cs.findbugs.plugin.eclipse项目中找到plugin.xm用manifest editor打开,在build选项卡中add Library:findbugs-plugin.jar,选中findbugs-plugin.jar,add folder:src
在findbugs项目中找到MANIFEST.MF,在build中add Library:findbugs.jar,选中findbugs-plugin.jar,add folder:src/java,src/java5,src/tools,src/antTask
开发新规则:
1.首先认识几个文件
Findbugs.xml
对于每一个新的检测器,在 FindBugs.xml 文件中增加一个 Detector 元素和一个 BugPattern 元素。 Detector 元素指定用于实现检测器的类以及它是快速还是慢速检测器。其中reports属性是和edu.umd.cs.findbugs.detect中类report的错误相对应的和Bugpattern中的type一致且唯一。
category 属性是枚举类型。
它是以下类型中的一种:
CORRECTNESS :一般正确性问题
MT_CORRECTNESS :多线程正确性问题
MALICIOUS_CODE :如果公开给恶意代码,有可能成为攻击点
PERFORMANCE :性能问题  
Message.xml
messages.xml 文件由三个元素组成: Detector 、 BugPattern 和 BugCode 。检测器的 class 属性应当指定检测器的类名。 Details 元素包含检测器的简单 HTML 描述,这里面主要写错误的提示信息。
FindBugs 利用了 Byte Code Engineering Library,称为 BCEL,以实现其检测器。所有字节码扫描检测器都基于 visitor 模式。侧重于两个方法------ visit(Code) 和 sawOpcode(int) 。在 FindBugs 分析类时,它会在分析方法内容时调用 visit(Code) 方法。与此类似,FindBugs 在分析方法正文中的每一个操作码时调用 sawOpcode(int) 方法。

下面我们看一个列子:在企业级开发中,是不允许用System.out来输出信息的,必须要用log日志来打印出信息,所以我们就增加一个findbugs的新规则发现代码中有system.out的时候就给用户提示,一下是开发步骤
先看一段通过javap反编的java代码对比
源码:
Java代码
view plaincopy to clipboardprint?
public class Test{      
    public static void main(String[] args){      
        String str="pass";      
        if(str.equals("pass")){      
            System.out.println("str is pass");        
        }      
    }      
}   
public class Test{   
    public static void main(String[] args){   
        String str="pass";   
        if(str.equals("pass")){   
            System.out.println("str is pass");     
        }   
    }   
}   


反编:
Java代码
view plaincopy to clipboardprint?
Compiled from "Test.java"     
public class Test extends java.lang.Object{      
public Test();      
  Code:      
   0:   aload_0      
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V      
   4:   return     
     
public static void main(java.lang.String[]);      
  Code:      
   0:   ldc #2; //String pass      
   2:   astore_1      
   3:   aload_1      
   4:   ldc #2; //String pass      
   6:   invokevirtual   #3; //Method java/lang/String.equals:(Ljava/lang/Object;)Z      
   9:   ifeq    20     
   12:  getstatic   #4; //Field java/lang/System.out:Ljava/io/PrintStream;      
   15:  ldc #5; //String str is pass      
   17:  invokevirtual   #6; //Method java/io/PrintStream.println:(Ljava/lang/String;)V      
   20:  return     
     
}   
Compiled from "Test.java"  
public class Test extends java.lang.Object{   
public Test();   
  Code:   
   0:   aload_0   
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V   
   4:   return  
  
public static void main(java.lang.String[]);   
  Code:   
   0:   ldc #2; //String pass   
   2:   astore_1   
   3:   aload_1   
   4:   ldc #2; //String pass   
   6:   invokevirtual   #3; //Method java/lang/String.equals:(Ljava/lang/Object;)Z   
   9:   ifeq    20  
   12:  getstatic   #4; //Field java/lang/System.out:Ljava/io/PrintStream;   
   15:  ldc #5; //String str is pass   
   17:  invokevirtual   #6; //Method java/io/PrintStream.println:(Ljava/lang/String;)V   
   20:  return  
  
}  
  
通过反编的代码我们可以看到调用system.out.println的时候是通过

12: getstatic #4; //Field java/lang/System.out:Ljava/io/PrintStream;
这句来执行的,所以我们只要找到getstatic指令,并判断方法调用是System.out就可以知道是用了System.out,就可以声明bug并且报告bug
findbugs代码
Java代码
view plaincopy to clipboardprint?
package edu.umd.cs.findbugs.detect;   
  
import org.apache.bcel.classfile.Code;   
  
import edu.umd.cs.findbugs.BugInstance;   
import edu.umd.cs.findbugs.BugReporter;   
import edu.umd.cs.findbugs.bcel.OpcodeStackDetector;   
  
/**  
* @author bo  
* 这个规则类用于判断System.out和System.error这种情况  
*/  
public class ForbiddenSystemClass extends OpcodeStackDetector {   
BugReporter bugReporter;   
  
public ForbiddenSystemClass(BugReporter bugReporter) {   
  this.bugReporter = bugReporter;   
}   
  
/**  
  * visit方法,在每次进入字节码方法的时候调用  
  * 在每次进入新方法的时候清空标志位  
  */  
@Override  
public void visit(Code obj) {   
  super.visit(obj);   
}   
  
/**  
  * 每扫描一条字节码就会进入sawOpcode方法  
  *   
  * @param seen  字节码的枚举值  
  */  
@Override  
public void sawOpcode(int seen) {   
  if (seen == GETSTATIC) {   
   if (getClassConstantOperand().equals("java/lang/System")   
           && (getNameConstantOperand().equals("out") || getNameConstantOperand().equals("error"))) {   
    BugInstance bug = new BugInstance(this, "ALP_SYSTEMCLASS", NORMAL_PRIORITY).addClassAndMethod(this)   
            .addSourceLine(this, getPC());   
    bug.addInt(getPC());   
    bugReporter.reportBug(bug);   
   }   
  }   
}   
}  
package edu.umd.cs.findbugs.detect;
import org.apache.bcel.classfile.Code;
import edu.umd.cs.findbugs.BugInstance;
import edu.umd.cs.findbugs.BugReporter;
import edu.umd.cs.findbugs.bcel.OpcodeStackDetector;
/**
* @author bo
* 这个规则类用于判断System.out和System.error这种情况
*/
public class ForbiddenSystemClass extends OpcodeStackDetector {
BugReporter bugReporter;
public ForbiddenSystemClass(BugReporter bugReporter) {
  this.bugReporter = bugReporter;
}
/**
  * visit方法,在每次进入字节码方法的时候调用
  * 在每次进入新方法的时候清空标志位
  */
@Override
public void visit(Code obj) {
  super.visit(obj);
}
/**
  * 每扫描一条字节码就会进入sawOpcode方法
  *
  * @param seen  字节码的枚举值
  */
@Override
public void sawOpcode(int seen) {
  if (seen == GETSTATIC) {
   if (getClassConstantOperand().equals("java/lang/System")
           && (getNameConstantOperand().equals("out") || getNameConstantOperand().equals("error"))) {
    BugInstance bug = new BugInstance(this, "ALP_SYSTEMCLASS", NORMAL_PRIORITY).addClassAndMethod(this)
            .addSourceLine(this, getPC());
    bug.addInt(getPC());
    bugReporter.reportBug(bug);
   }
  }
}
}
  
new BugInstance(this, "ALP_SYSTEMCLASS", NORMAL_PRIORITY)
ALP_SYSTEMCLASS这个和findbugs.xml、message.xml中相对应
findbugs的新规则开发使用了visit模式,我们只需要实现visit方法sawOpcode方法即可,当然实现复杂功能,有不同的父类
在findbugs.xml中把自己的Detector 声明出来
Xml代码
view plaincopy to clipboardprint?
<Detector class="edu.umd.cs.findbugs.detect.AlipayForbiddenSystemClass"     
   speed="fast"  
     reports="ALP_SYSTEMCLASS"  
     hidden="false" />  
<Detector class="edu.umd.cs.findbugs.detect.AlipayForbiddenSystemClass"  
   speed="fast"
     reports="ALP_SYSTEMCLASS"
     hidden="false" />
   
message.xml
view plaincopy to clipboardprint?
<Detector class="edu.umd.cs.findbugs.detect.ForbiddenSystemClass">  
   <Details>  
    <!--[CDATA[   
    <p>线上代码不能出现System.out   
    <p>请使用log日志形式打印   
    ]]>  
   </Details>  
  </Detector>  
  
<BugPattern type="ALP_ALIPAY_SYSTEMCLASS">  
    <ShortDescription>线上代码不能出现System.out</ShortDescription>  
    <LongDescription>{1}线上代码不能出现System.out,请使用log形式输出</LongDescription>  
    <Details>  
  <![CDATA[   
    <p>不能使用System.out和System.err,请使用log</p>  
  ]]-->  
    </Details>  
  </BugPattern>  
<Detector class="edu.umd.cs.findbugs.detect.ForbiddenSystemClass">
   <Details>
    <!--[CDATA[
    <p>线上代码不能出现System.out
    <p>请使用log日志形式打印
    ]]>
   </Details>
  </Detector>
<BugPattern type="ALP_ALIPAY_SYSTEMCLASS">
    <ShortDescription>线上代码不能出现System.out</ShortDescription>
    <LongDescription>{1}线上代码不能出现System.out,请使用log形式输出</LongDescription>
    <Details>
  <![CDATA[
    <p>不能使用System.out和System.err,请使用log</p>
  ]]-->
    </Details>
  </BugPattern>

这里配置错误的显示信息
最终把
java类、xml按照下面这个ant脚本的描述进行打包
view plaincopy to clipboardprint?
<project name="findbugs-plugin" default="build">  
  
<property name="FindBugs.home" value="D:/Program Files/eclipse/plugins/edu.umd.cs.findbugs.plugin.eclipse_1.3.8.20090315"></property>这里是你的eclipse中findbugs的路径   
<target name="build">  
<jar destfile="AlipayFindBugsRules.jar">  
  <fileset dir="bin"/>  
  <fileset dir="src"/>  
  <zipfileset dir="etc" includes="*.xml" prefix=""></zipfileset>  
</jar>  
<copy file="FindBugsRules.jar" todir="${FindBugs.home}/plugin" />  
</target>  
  
</project>  
<project name="findbugs-plugin" default="build">
<property name="FindBugs.home" value="D:/Program Files/eclipse/plugins/edu.umd.cs.findbugs.plugin.eclipse_1.3.8.20090315"></property>这里是你的eclipse中findbugs的路径
<target name="build">
<jar destfile="AlipayFindBugsRules.jar">
  <fileset dir="bin"/>
  <fileset dir="src"/>
  <zipfileset dir="etc" includes="*.xml" prefix=""></zipfileset>
</jar>
<copy file="FindBugsRules.jar" todir="${FindBugs.home}/plugin" />
</target>
</project>
  
命令行ant就打包了,把打好的jar包放到findbugs插件的plugin目录下,重启eclipse就可以使用新的规则了


http://www.niftyadmin.cn/n/656115.html

相关文章

MySQL计算日期的函数DATE_SUB(d,INTERVAL expr type)

MySQL计算日期的函数DATE_SUB(d,INTERVAL expr type) DATE_SUB(d,INTERVAL expr type)函数返回起始日期d减去一个时间段后的日期。 expr是一个表达式&#xff0c;用来指定从起始日期添加或减去的时间间隔值。 expr是一个字符串。对于负值的时间间隔&#xff0c;它可以用一个负号…

QTP中提示当前安全设置禁止安全运行该页中的activeX控件的解决方法

在录制好的QTP脚本中&#xff0c;点击修改这些脚本时,可能提示"当前安全设置禁止安全运行该页中的activeX控件"。关于这个Active的对话提示窗口&#xff0c;问题在于QTP的设置&#xff0c;要消除该提示窗口&#xff0c;应对QTP作如下设置&#xff1a;toos---options.…

python123第三周_tensorflow2保存和加载模型

tensorflow2保存和加载模型 (tensorflow2.0官方教程翻译) 模型进度可以在训练期间和训练后保存。这意味着模型可以在它停止的地方继续&#xff0c;并避免长时间的训练。保存还意味着您可以共享您的模型&#xff0c;其他人可以重新创建您的工作。当发布研究模型和技术时&#xf…

【转】如何使用QTP自动化测试Flex3.0

2008.4.1 10:11 作者&#xff1a;van以前一直想使用QTP来自动化测试Flex。但只支持Flex2.0。研究了很久都没有完全摸清。 最近一直研究RIATest&#xff0c;把整个Flex也彻底的研究了下。发现触类旁通。今天终于在QTP中实现了Flex3.0的自动化测试。 在这里把经验分享给大家。如果…

python turtle画熊猫_python绘图:matplotlib和pandas的应用

在进行数据分析时&#xff0c;绘图是必不可少的模式探索方式。用Python进行数据分析时&#xff0c;matplotlib和pandas是最常用到的两个库。 1、matplotlib库的应用 准备工作如下&#xff1a;打开ipython&#xff0c;输入命令分别导入numpy和matplotlib.pylab库。 import numpy…

python学习之常见错误

以中国大学定向排名爬虫为例 一、for tr in soup.find(tbody).children: AttributeError: NoneType object has no attribute children 它告诉我们从soup中获取到的网页结构内容tbody出现问题&#xff0c;这就要从函数getHTMLText(url)中来找解决的办法&#xff0c;网上有的同学…

南方h5手簿使用说明书_如何进行坐标转换(RT K手簿或COO RD)

面介绍大地坐标和空间坐标之间的相互转换。南方测绘步骤&#xff1a;“工具” - “坐标转换”在源类型上勾选 BLH &#xff0c;目标类型上勾选 XYZ &#xff0c;输入对应的源大地坐标&#xff0c;点击“正向转换”&#xff0c;即可得到转换之后的空间坐标&#xff0c;如下图所示…

python语法基础题你好_入门Python,从这15个基础语法开始!

Python简单易学&#xff0c;但又博大精深。许多人号称精通Python&#xff0c;却不会写Pythonic的代码&#xff0c;对很多常用包的使用也并不熟悉。学海无涯&#xff0c;我们先来了解一些Python中最基本的内容。 Python的特点 解释型语言&#xff0c;无需编译即可运行 提供了交互…