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

大家都知道java开发的应用,代码量都是很庞大的,并且所有的代码不可能是一个人完成的,如何保证我们代码的高质量呢?静态扫描工具findbugs是不错的选择

java应用最常见的也就是NullPointException问题了。平时我们做小的项目出几个NPE没什么太大的影响,打几个错误日志,下次 修复掉就行了。但是如果是淘宝、支付宝这样的大型系统,每天用户量很大,可能一个NPE就会影响到很多用户的系统使用。findbugs会容易的找出这些 问题。

有的时候findbugs不能满足我们的需求,我们需要在代码扫描阶段就发现更多的问题,那么就需要开发针对自己需求的findbugs规则。比 如:生产环境的代码中是不允许有System.out.prinln("xxxxx");这样的信息出现的,必须使用log来记录日志,所以我们就可以专 门写一条规则来检测代码里面是否存在System.out,如果存在就给出提示。

同样的,在使用log日志的时候,必须要先判断日志的级别然后再使用log.debug(""),所以我们可以定义一条日志来检测代码中是否存在没有使用if条件判断就直接log.debug(),有的话给出提示。

进入正题,通过找代码中是否存在System.out来讲解findbugs规则的开发过程

效果:

准备工作:

1 findbugs源码的下载下载路径:

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代码

  1. public   class  Test{     
  2.     public   static   void  main(String[] args){     
  3.         String str="pass" ;     
  4.         if (str.equals( "pass" )){     
  5.             System.out.println("str is pass" );       
  6.         }     
  7.     }     
  8. }    

 


反编:

Java代码

  1. Compiled from  "Test.java"     
  2. public   class  Test  extends  java.lang.Object{     
  3. public  Test();     
  4.   Code:     
  5.    0 :   aload_0     
  6.    1 :   invokespecial   # 1//Method java/lang/Object."<init>":()V      
  7.    4 :    return     
  8.     
  9. public   static   void  main(java.lang.String[]);     
  10.   Code:     
  11.    0 :   ldc # 2//String pass      
  12.    2 :   astore_1     
  13.    3 :   aload_1     
  14.    4 :   ldc # 2//String pass      
  15.    6 :   invokevirtual   # 3//Method java/lang/String.equals:(Ljava/lang/Object;)Z      
  16.    9 :   ifeq     20     
  17.    12 :  getstatic   # 4//Field java/lang/System.out:Ljava/io/PrintStream;      
  18.    15 :  ldc # 5//String str is pass      
  19.    17 :  invokevirtual   # 6//Method java/io/PrintStream.println:(Ljava/lang/String;)V      
  20.    20 :   return     
  21.     
  22. }    

  
通过反编的代码我们可以看到调用system.out.println的时候是通过


12: getstatic #4; //Field java/lang/System.out:Ljava/io/PrintStream;
这句来执行的,所以我们只要找到getstatic指令,并判断方法调用是System.out就可以知道是用了System.out,就可以声明bug并且报告bug

findbugs代码

Java代码

  1. package  edu.umd.cs.findbugs.detect;  
  2.   
  3. import  org.apache.bcel.classfile.Code;  
  4.   
  5. import  edu.umd.cs.findbugs.BugInstance;  
  6. import  edu.umd.cs.findbugs.BugReporter;  
  7. import  edu.umd.cs.findbugs.bcel.OpcodeStackDetector;  
  8.   
  9. /**  
  10.  * @author bo  
  11.  * 这个规则类用于判断System.out和System.error这种情况  
  12.  */   
  13. public   class  ForbiddenSystemClass  extends  OpcodeStackDetector {  
  14.  BugReporter bugReporter;  
  15.   
  16.  public  ForbiddenSystemClass(BugReporter bugReporter) {  
  17.   this .bugReporter = bugReporter;  
  18.  }  
  19.   
  20.  /**  
  21.   * visit方法,在每次进入字节码方法的时候调用  
  22.   * 在每次进入新方法的时候清空标志位  
  23.   */   
  24.  @Override   
  25.  public   void  visit(Code obj) {  
  26.   super .visit(obj);  
  27.  }  
  28.   
  29.  /**  
  30.   * 每扫描一条字节码就会进入sawOpcode方法  
  31.   *   
  32.   * @param seen  字节码的枚举值  
  33.   */   
  34.  @Override   
  35.  public   void  sawOpcode( int  seen) {  
  36.   if  (seen == GETSTATIC) {  
  37.    if  (getClassConstantOperand().equals( "java/lang/System" )  
  38.            && (getNameConstantOperand().equals("out" ) || getNameConstantOperand().equals( "error" ))) {  
  39.     BugInstance bug = new  BugInstance( this"ALP_SYSTEMCLASS" , NORMAL_PRIORITY).addClassAndMethod( this )  
  40.             .addSourceLine(this , getPC());  
  41.     bug.addInt(getPC());  
  42.     bugReporter.reportBug(bug);  
  43.    }  
  44.   }  
  45.  }  
  46. }  

  

new BugInstance(this, "ALP_SYSTEMCLASS", NORMAL_PRIORITY)
ALP_SYSTEMCLASS这个和findbugs.xml、message.xml中相对应
findbugs的新规则开发使用了visit模式,我们只需要实现visit方法sawOpcode方法即可,当然实现复杂功能,有不同的父类

在findbugs.xml中把自己的Detector 声明出来

Xml代码

  1. < Detector   class = "edu.umd.cs.findbugs.detect.AlipayForbiddenSystemClass"     
  2.    speed = "fast"   
  3.      reports = "ALP_SYSTEMCLASS"   
  4.      hidden = "false"   />   

  

message.xml

  1. < Detector   class = "edu.umd.cs.findbugs.detect.ForbiddenSystemClass" >   
  2.    < Details >   
  3.     <!--[CDATA[  
  4.     < p > 线上代码不能出现System.out  
  5.     < p > 请使用log日志形式打印  
  6.     ]]>   
  7.    </ Details >   
  8.   </ Detector >   
  9.   
  10. < BugPattern   type = "ALP_ALIPAY_SYSTEMCLASS" >   
  11.     < ShortDescription > 线上代码不能出现System.out </ ShortDescription >   
  12.     < LongDescription > {1}线上代码不能出现System.out,请使用log形式输出 </ LongDescription >   
  13.     < Details >   
  14.   <![CDATA[  
  15.     < p > 不能使用System.out和System.err,请使用log </ p >   
  16.   ]]-->   
  17.     </ Details >   
  18.   </ BugPattern >   

这里配置错误的显示信息

最终把
java类、xml按照下面这个ant脚本的描述进行打包

  1. < project   name = "findbugs-plugin"   default = "build" >   
  2.   
  3.  < property   name = "FindBugs.home"   value = "D:/Program Files/eclipse/plugins/edu.umd.cs.findbugs.plugin.eclipse_1.3.8.20090315" > </ property > 这里是你的eclipse中findbugs的路径  
  4.  < target   name = "build" >   
  5.  < jar   destfile = "AlipayFindBugsRules.jar" >   
  6.   < fileset   dir = "bin" />   
  7.   < fileset   dir = "src" />   
  8.   < zipfileset   dir = "etc"   includes = "*.xml"   prefix = "" > </ zipfileset >   
  9.  </ jar >   
  10.  < copy   file = "FindBugsRules.jar"   todir = "${FindBugs.home}/plugin"   />   
  11. </ target >   
  12.   
  13. </ project >   

  
命令行ant就打包了,把打好的jar包放到findbugs插件的plugin目录下,重启eclipse就可以使用新的规则了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值