靜態代碼檢查工具 FindBugs

靜態代碼檢查工具 FindBugs
使用 FindBugs的原因和方法
 
靜態分析工具承諾無需開發人員費勁就能找出代碼中已有的缺陷。當然,如果有多年的編寫經驗,就會知道這些承諾並不是一定能兌現。儘管如此,好的靜態分析工具仍然是工具箱中的無價之寶。在這個由兩部分組成的系列文章的第一部分中,高級軟件工程師 Chris Grindstaff 分析了 FindBugs如何幫助提高代碼質量以及排除隱含的缺陷。
代碼質量工具的一個問題是它們容易爲開發人員提供大量但並非真正問題的問題——僞問題(false positives。出現僞問題時,開發人員要學會忽略工具的輸出或者放棄它。FindBugs的設計者 David Hovemeyer William Pugh注意到了這個問題,並努力減少他們所報告的僞問題數量。與其他靜態分析工具不同,FindBugs不注重樣式或者格式,它試圖只尋找真正的缺陷或者潛在的性能問題。
FindBugs是什麼?
FindBugs是一個靜態分析工具,它檢查類或者 JAR文件(注意它分析是不是JAVA源文件而是編繹後CLASS類),將字節碼與一組缺陷模式進行對比以發現可能的問題。有了靜態分析工具,就可以在不實際運行程序的情況對軟件進行分析。不是通過分析類文件的形式或結構來確定程序的意圖,而是通常使用 Visitor模式(請參閱參考資料)。圖 1顯示了分析一個匿名項目的結果(爲防止可怕的犯罪,這裏不給出它的名字):
 1. FindBugs UI
 

2.安裝Eclipse的FindBugs插件

可以在下面的地址

http://findbugs.sourceforge.net/downloads.html

打開頁面內容如下:

下載FindBugs軟件以及eclipse和blueJ的插件。

The Eclipse plugin may also be obtained from one of the FindBugs Eclipse plugin update sites: --FindBugs插件的更新地址有很多,根據類型的不同,包括以下幾個:

單擊上面鏈接即可下載(另存).

也可以在下面的地址:

http://prdownloads.sourceforge.net/findbugs

下載插件的zip文件,將其解壓縮到eclipse的plugin目錄(<eclipse_install_dir>/plugins)。

安裝完插件後,可以使用Help-->About Eclipse Platform-->Plug-in Details來查看FindBugs插件的使用方法。

3.       在Eclipse中使用FindBugs插件

運行FindBugs插件的方法很簡單,選中一個Java工程後,點擊右鍵,選擇Find Bugs,這時就會啓動FindBugs,並且會在有問題的源代碼中顯示標記。

可以自定義FindBugs的運行方式:查看Java工程的屬性對話框,選擇FindBugs的屬性頁,可以看到如下的選項:

→       啓用/禁用”自動運行FindBugs”複選框---是否在每次修改時進行FindBugs的檢查

→       選擇最小的警告優先級,並啓用bug的分類---這些選項用於決定顯示哪些問題,例如,如果選擇Medium警告優先級的話,只有Medium和Hign優先級的警告纔會被顯示,類似的,如果不選中Style複選框的話,那麼有關Style類別的警告也不會被顯示。

→       選擇檢查引擎:對指定的工程啓用那些detectors。

具體的設置畫面如下:


(設置detectors和是否自動運行FindBugs)


(設置啓用的分類)

 

常見的類型如下:

· 正確性(Correctness):這種歸類下的問題在某種情況下會導致bug,比如錯誤的強制類型轉換等。

· 最佳實踐反例(Bad practice):這種類別下的代碼違反了公認的最佳實踐標準,比如某個類實現了equals方法但未實現hashCode方法等。

· 多線程正確性(Multithreaded correctness):關注於同步和多線程問題。

· 性能(Performance):潛在的性能問題。

· 安全(Security):安全相關。

· 高危(Dodgy):FindBugs團隊認爲該類型下的問題代碼導致bug的可能性很高。

在Eclipse中安裝FindBugs插件

   下載Eclipse plugin 的版本,解壓zip文件。

   將解壓後的文件放到Eclipse的Plugin中。

   重新啓動Eclipse 。

 

    我使用的是MyEclipse8.5可能路徑和大家的不太一樣,我是放到了路徑Genuitec/MyEclipse 8.5/dropins下面 

 

在Eclipse中使用FindBugs

重新啓動eclipse

打開FindBugs視圖 

 

執行Find Bug 任務

右鍵單擊你要檢測的工程、包或文件,-->Find Bugs-->Find Bugs。

check完成後將在Bug Explorer視圖中看到問題列表,該列表以問題類型組織。 

 

展開列表,雙擊列表中具體的問題就可以定位的具體的代碼行。 

配置FindBugs
在這裏可以對FindBugs規則等進行詳細設置。 
  選擇你的項目,右鍵 => Properties => FindBugs =>

 

1 Run Automatically開關

設置Eclipse自動編譯開關-----即主窗口菜單Project---Build Automatically這個選項勾上就行了.

當此項選中後,FindBugs將會在你修改Java類時自動運行,如你設置了Eclipse自動編譯開關後,當你修改完Java文件保存,FindBugs就會運行,並將相應的信息顯示出來。
當此項沒有選中,你只能每次在需要的時候自己去運行FindBugs來檢查你的代碼。

2 Detector Configuration選擇項
在這裏你可以選擇所要進行檢查的相關的Bug Pattern條目,你可以根據需要選擇或去掉相應的 檢查條件。 

3 Minimum priority to report選擇項
這個選擇項是讓你選擇哪個級別的信息進行顯示,有Low、Medium、High三個選擇項可以選擇,很類似於Log4J的級別設置啦。 比如:


你選擇了High選擇項,那麼只有是High級別的提示信息纔會被顯示。
你選擇了Medium選擇項,那麼只有是Medium和High級別的提示信息纔會被顯示。
你選擇了Low選擇項,那麼所有級別的提示信息都會被顯示。

4 Report bug categories選擇項
在這裏是一些顯示Bug分類的選擇:
Malicious code vulnerability關於惡意破壞代碼相關方面的
Correctness關於代碼正確性相關方面的
Internationalization關於代碼國際化相關方面的
Performance關於代碼性能相關方面的
Multithreaded correctness關於代碼多線程正確性相關方面的

另外FindBugs有UI頁面,可以單獨運行。也可以通過Ant以及命令行方式運行。

 

 

4.       在Ant中使用FindBugs

Ant作爲一個優秀的自動化構建軟件,大量的應用在Java軟件開發中(雖然有被Maven取代的危險)。FindBugs提供了集成在Ant中使用的Ant Task,可以在自動構建與部署的時候運行FindBugs。

將$FINDBUGS_HOME/lib/findbugs-ant.jar拷貝到$ANT_HOME/lib目錄下以後,就完成了FindBugs的Ant Task的安裝。(強烈建議使用FindBugs附帶的jar文件)

爲了將FindBugs任務集成到Ant腳本中,需要首先進行一個task的定義,如下面的片段所示:---下面ANT的XML內容介紹

<taskdef name=”findbugs” classname=”edu.umd.cs.findbugs.anttask.FindBugsTask” />

在定義了findbugs task之後,就可以使用了。下面是一個例子:

<property name="findbugs.home" value="/export/home/daveho/work/findbugs" /> 

<target name="findbugs" depends="jar">

<findbugs home="${findbugs.home}"

      output="xml"

      outputFile="bcel-fb.xml" >

<auxClasspath path="${basedir}/lib/Regex.jar" />

<sourcePath path="${basedir}/src/java" />

<class location="${basedir}/bin/bcel.jar" />

</findbugs>

</target>

findbugs元素必須有home屬性,用於指定FindBugs的安裝路徑。

這是就會在bcel.jar上執行FindBugs。FindBugs的運行結果會被以xml的格式保存在bcel-fb.xml文件中。一個輔助的jar文件被添加到auxClasspath元素中,因爲BCEL庫引用了它。

另外一個例子:

從http://findbugs.sourceforge.net/downloads.html下載最新版本的Findbugs,目前的版本是1.3.0, 於2007年11月8日發佈。把解壓後目錄複製到項目的lib目錄下,然後就可以和Ant配合使用了。FindBugs工作在j2se1.4.0或以後的版本中,需要至少256MB內存。         

在Ant腳本中,首先定義Findbugs的解壓目錄位置:      

<path id="findbugs.path" >     

    

     <fileset  dir ="${lib.home}/findbugs-1.3.0">     

    

        <include  name ="**/*.jar"/>     

  

     </fileset>     

    

</path>     

    

接着聲明Findbugs任務:     

    

<taskdef name="findbugs"       

    

classname="edu.umd.cs.findbugs.anttask.FindBugsTask"       

    

classpathref ="findbugs.path"/>     

    

然後建立Findbugs任務:     

    

<property name ="findbugs.home"  value ="${lib.home}/findbugs-1.3.0"/>     

    

<!--  定義findbugs的home,findbugs的task要使用  -->     

    

<target name ="findbugs">     

   

<findbugs home ="${findbugs.home}" includeFilter="${findbugs_include_filter}"    

    

excludeFilter="${findbugs_exclude_filter}"    

    

  jvmargs="-Xmx384m"  output ="html"       

    

outputFile ="d:/test.html">     

      <class location ="${build.home}/WEB-INF/classes/"/>     

 

     <!--  以上定義findbugs查找的類路徑  -->     

<auxClasspath path="${lib.home}/findbugs-1.3.0/lib/findbugs-ant.jar"/>     

  <auxClasspath>     

  <fileset dir="${build.home}/WEB-INF/lib" includes="**/*.jar" />     

</auxClasspath>     

   <!--  以上定義上述類所依賴的類路徑  -->     

    <sourcePath path ="${src.home}"/>     

  <!--  以上定義源代碼的路徑  -->     

    </findbugs >     

  

</target >     

    

最後運行ant findbugs即可。  

使用過濾器         

使用過濾器我們就可以定義使用哪些bug檢測器和針對哪些類進行檢查,因爲一旦項目比較龐大,那查看冗長的bug報告也是十分痛苦的事情。使用過濾器,過濾器用來包含或排除特殊的bug報告。這樣做有助於在特定的時間段內,聚焦我們的關注點。過濾器實際是在一個xml文件定義的,xml配置文件的內容如下:          

<FindBugsFilter>          

     <!--  所有類使用bugcode爲HE的檢測器  -->          

     <Match>          

         <BugCode  name ="HE"/>          

     </Match>          

     <!--  該類使用所有的bug檢測器  -->          

     <Match class ="com.foobar.AClass"/>            

     <!--  該類使用bugcode爲HE的檢測器  -->         

     <Match class ="com.foobar.BClass">         

         <BugCode  name ="HE"/>         

     </Match>         

     <!--  該類的AMethod和BMethod方法使用bugcode爲HE的檢測器  -->         

     <Match class ="com.foobar.CClass">          

         <Or>         

             <Method name ="AMethod"/>          

             <Method name ="BMethod"/>          

         </Or>          

         <BugCode name ="HE"/>          

     </Match>          

</FindBugsFilter>     

        

Findbugs過濾器的一些元素講解:         

<FindBugsFilter>          

     <!--  該類使用所有的bug檢測器  -->          

     <Match>         

       <Class name="com.foobar.MyClass" />         

     </Match>            

     <!--  該類使用bugcode爲HE的檢測器  -->          

     <Match class ="com.foobar.BClass">          

         <BugCode  name ="HE"/>          

     </Match>          

     <!--  該類通過指定縮寫名使用一些bug檢測器  -->         

     <Match>         

       <Class name="com.foobar.MyClass">         

       <Bug code="DE,UrF,SIC" />         

     </Match>         

     <!--  所有類使用bugcode爲HE的檢測器  -->          

     <Match>          

         <BugCode  name ="HE"/>         

     </Match>          

     <!--  所有類使用bugcode爲DE,UrF,SIC的檢測器  -->          

     <Match>         

       <Bug code="DE,UrF,SIC" />         

     </Match>         

     <!--  所有類通過指定檢測器種類使用某些檢測器  -->         

     <Match>         

       <Bug category="PERFORMANCE" />         

     </Match>         

     <!--  該類的指定方法使用bugcode爲DC的檢測器  -->          

     <Match>         

       <Class name="com.foobar.MyClass" />         

       <Or>         

       <Method name="frob" params="int,java.lang.String" returns="void" />         

       <Method name="blat" params="" returns="boolean" />         

       </Or>         

       <Bug code="DC" />         

     </Match>         

     <!--  該類的AMethod和BMethod方法使用bugcode爲DE,UrF,SIC的檢測器  -->          

     <Match>         

        <Class name="com.foobar.MyClass" />         

         <Or>          

             <Method name ="AMethod"/>          

             <Method name ="BMethod"/>          

         </Or>          

         <BugCode name ="DE,UrF,SIC "/>          

     </Match>          

     <!—該類的指定方法使用bug模式爲OS_OPEN_STREAM的檢測器 -->         

     <Match>         

       <Class name="com.foobar.MyClass" />         

       <Method name="writeDataToFile" />         

       <Bug pattern="OS_OPEN_STREAM" />        

     </Match>         

    <!—該類的某個方法使用優先級爲2的bug模式DLS_DEAD_LOCAL_STORE 的檢測器-->         

    <Match>         

      <Class name="com.foobar.MyClass" />         

      <Method name="someMethod" />         

      <Bug pattern="DLS_DEAD_LOCAL_STORE" />         

      <Priority value="2" />         

    </Match>         

    <!—代碼的指定部分使用指定bugcode或bug模式的檢測器 -->        

    <!—所有包的信息類使用bugcode爲UUF的檢測器-->         

    <Match>          

      <Class name="~.*/.Messages" />         

      <Bug code="UUF" />        

    </Match>         

    <!—所有內部包使用bugcode爲MS的檢測器-->         

    <Match>         

      <Package name="~.*/.internal" />         

      <Bug code="MS" />         

    </Match>         

    <!—ui包層使用bug模式爲SIC_INNER_SHOULD_BE_STATIC_ANON的檢測器-->         

    <Match>         

      <Package name="~com/.foobar/.fooproject/.ui.*" />         

      <Bug pattern="SIC_INNER_SHOULD_BE_STATIC_ANON" />       

    </Match>         

    <!—帶指定標誌的成員域或方法使用指定bugcode或bug模式的檢測器-->         

    <!—所有類中的void main(String[])方法使用bug模式爲DM_EXIT的檢測器-->        

    <Match>         

      <Method returns="void" name="main" params="java.lang.String[]" />         

      <Bug pattern="DM_EXIT" />         

    </Match>         

    <!—所有類中的com.foobar.DebugInfo型的域使用bugcode爲UuF的檢測器-->         

    <Match>         

      <Field type="com.foobar.DebugInfo" />         

      <Bug code="UuF" />         

    </Match>         

</FindBugsFilter>    

 

   

 

 

關於findbugs任務的詳細說明,如下:

class

    嵌套元素指定要分析的類。這個元素必須指定一個location屬性,location屬性的名字爲archive文件(jar,zip等)、目錄或者class文件。可以爲一個findbugs元素指定多個class元素。

auxClasspath

    可選的嵌套元素,用於指定要分析的類所引用的類,但是並不對引用的類進行分析。

sourcePath

    可選的嵌套元素,指定Java源代碼的目錄。

home

    必須的屬性,findbugs的安裝目錄。

quietErrors

    可選的布爾型屬性。如果是true的話,報告嚴重的分析錯誤和丟失的類。默認情況下爲false。

reportLevel

    可選的屬性。指定優先級別。如果是low的話,那麼報告所有的bug,如果是medium(缺省值),報告medium和high優先級的bug。

output

    可選屬性,設置輸出格式。

stylesheet

    可選屬性,指定生成html時使用的樣式表。

sort

    可選屬性,如果輸出屬性設置爲text,該屬性指定是否對輸出結果根據class進行排序,默認爲true。

outputFile

    可選屬性,指定輸出文件。

debug

    可選的布爾型屬性,是否打印分析過程中的日誌。默認值爲false。

effort

    設置分析工作的等級,可以爲min、default和max。

conserveSpace

    和min effort一樣的功能。

workHard

    和max effort一樣的功能。

visitors

    可選屬性,指定逗號分隔的列表,指定要運行的detectors。

omitVisitors

    可選屬性,忽略detectors。摺合visitors屬性類似,只是不指定不運行哪些detectors。

excludeFilter

    可選屬性,指定排除的Filter。

includeFilter

    可選屬性,指定包含的Filter。

projectFile

    可選屬性,指定項目的名稱。

jvmargs

    可選屬性,指定JVM變量。

systemProperty

    系統屬性。

timeout

    可選屬性,指定超市的時間,默認爲600,000毫秒,即10分鐘。

failOnError

    可選屬性,指定是否在運行FindBugs出現異常時停止構建過程,默認爲false。

errorProperty

    可選屬性,如果在運行FindBugs時發生錯誤,指定屬性的值爲true。

warningsProperty

    可選屬性,如果在運行FindBugs時發生警告,指定屬性的值爲true。

build.xml實例

Findbugs官方提供了Ant的findbugs操作方法,我們可以通過這樣一個build.xml文件來使用findbugs。

<project name="項目名" default="all">

<property name="findbugs.home" value="findbugs解壓路徑" />

              <path id="findbugs.path">

                  <fileset dir="findbugs解壓路徑">

                        <include name="**/*.jar" />

                   </fileset>

              </path>

              <taskdef name="findbugs"

                   classname="edu.umd.cs.findbugs.anttask.FindBugsTask"

                   classpathref="findbugs.path" />

              <!--  定義findbugs的home,findbugs的task要使用  -->

              <target name="findbugs">

                   <findbugs home="${findbugs.home}"

                        output="xml:withMessages" outputFile="生成的文件">

 

                        <!--  以上定義findbugs查找的類路徑  -->

                        <auxClasspath path="${findbugs.home}/lib/findbugs-ant.jar" />

                        <auxClasspath>

                            <fileset dir="lib"

                            includes="*.jar" />

                        </auxClasspath>

                        <sourcePath path="源文件路徑" />

                        <class location="生成類路徑" />

                   </findbugs>

          </target>

     </project>

比如:我這裏有一個我放在博客上的項目的findbugs的ant操作的build文件。

<project name="Calendar" default="all">

<property name="findbugs.home" value="../../findbugs-1.3.8" />

              <path id="findbugs.path">

                  <fileset dir="../../findbugs-1.3.8">

                        <include name="**/*.jar" />

                   </fileset>

              </path>

              <taskdef name="findbugs"

                   classname="edu.umd.cs.findbugs.anttask.FindBugsTask"

                   classpathref="findbugs.path" />

              <!--  定義findbugs的home,findbugs的task要使用  -->

              <target name="findbugs">

                   <mkdir dir="target/findbugs"/>

                   <findbugs home="${findbugs.home}"

                        output="xml:withMessages" outputFile="target/findbugs/calendar-fb.xml">

                        <!--  以上定義findbugs查找的類路徑  -->

                        <auxClasspath path="${findbugs.home}/lib/findbugs-ant.jar" />

                        <auxClasspath>

                            <fileset dir="lib"

                            includes="*.jar" />

                        </auxClasspath>

                        <sourcePath path="src" />

                        <class location="target/classes" />

                   </findbugs>

          </target>

     </project>

設置好Ant的環境後,在命令中使用ant -f build.xml,或者在Eclipse直接運行build.xml文件,運行後生成了一個xml文件,如果你想用Html的格式查看findbugs的結果,可以把output屬性設爲:html。這樣就可以通過Html來查看findbugs的結果了。

最簡單的例子如下:

<project name="findbugsproject" default="findbugs">
<property name="findbugs.home" value="findbugs-1.3.9" />
 <taskdef name="findbugs" classname="edu.umd.cs.findbugs.anttask.FindBugsTask"/> 
 <target name="findbugs">            
       <findbugs home="${findbugs.home}" output="html" outputFile="aaa.html" effort="default">
          <class location="Client/classes" />                    
          <sourcePath path="Client/src" />
       </findbugs>
 </target> 
</project>

提供的Swing工具

       Ant操作是專家級的操作,一般對於Java不是很熟悉的人,寫build.xml文件。比起Ant來,使用Findbugs提供的Swing工具會使Findbugs的操作更加簡單。運行Findbugs解壓包中的bin文件夾下的findbugs.bat文件。

Findbugs的Swing工具初始主界面如下:

 findbugs-1.3.9.zip ----WINDOWS下載FindBugs軟件,可獨立運行.並可在Ant中使用FindBugs,這個下截文件解壓後目錄中有一個BAT文件,打開後就能看到SWING界面

在分析項目之前,我們必須要新建一個項目來分析,選擇文件->新建

顯示新建項目的界面如下圖:
然後添加要分析的類包和目錄(可以選擇編譯好的類所在的文件夾,也可以選擇生成的jar包),再添加輔助類所在的文件夾和源文件所在的文件夾(java文件所在的文件夾)。再點擊完成就可以建立一個要分析的項目。 

建立項目後,會自動先自動開始解析項目。

解析後界面:

 

其中左邊是缺陷的樹結構列表,點擊其中一個Bug,可以在右邊的界面中,顯示Bugs的源文件以及所在的位置。

 

5.       命令行下使用FindBugs和圖形化的FindBugs的使用

此處不介紹這種使用方式,詳細內容參考findbugs manual。

6.       FindBugs Bug描述

筆者認爲其實最重要的還是FindBugs可以幫助我們找出哪些Bugs。

但是FindBugs的Bug描述是在太多,可以參考:

http://findbugs.sourceforge.net/bugDescriptions.html

 
讓我們看幾個 FindBugs可以發現的問題。
下面的列表沒有包括 FindBug可以找到的所有問題。相反,我側重於一些更有意思的問題。
檢測器:找出 hash equals不匹配
這個檢測器尋找與equals()hashCode()的實現相關的幾個問題。這兩個方法非常重要,因爲幾乎所有基於集合的類—— ListMapSet等都調用它們。一般來說,這個檢測器尋找兩種不同類型的問題——當一個類:
  • 重寫對象的equals()方法,但是沒有重寫它的hashCode方法,或者相反的情況時。
  • 定義一個 co-variant版本的equals()compareTo()方法。例如,Bob類定義其equals()方法爲布爾equals(Bob),它覆蓋了對象中定義的equals()方法。因爲 Java 代碼在編譯時解析重載方法的方式,在運行時使用的幾乎總是在對象中定義的這個版本的方法,而不是在Bob中定義的那一個(除非顯式將equals()方法的參數強制轉換爲Bob類型)。因此,當這個類的一個實例放入到類集合中的任何一箇中時,使用的是Object.equals()版本的方法,而不是在Bob中定義的版本。在這種情況下,Bob類應當定義一個接受類型爲Object的參數的equals()方法。
檢測器:忽略方法返回值
這個檢測器查找代碼中忽略了不應該忽略的方法返回值的地方。這種情況的一個常見例子是在調用String方法時,如在清單 1中:
清單 1.忽略返回值的例子
1  String aString = "bob";
2  b.replace('b', 'p');
3  if(b.equals("pop"))
 
這個錯誤很常見。在第 2行,程序員認爲他已經用 p替換了字符串中的所有 b。確實是這樣,但是他忘記了字符串是不可變的。所有這類方法都返回一個新字符串,而從來不會改變消息的接收者。
檢測器:Null指針對 null的解引用(dereference)和冗餘比較
這個檢測器查找兩類問題。它查找代碼路徑將會或者可能造成 null指針異常的情況,它還查找對 null的冗餘比較的情況。例如,如果兩個比較值都爲 null,那麼它們就是冗餘的並可能表明代碼錯誤。FindBugs在可以確定一個值爲 null而另一個值不爲 null時,檢測類似的錯誤,如清單 2所示:
清單 2. Null指針示例
1  Person person = aMap.get("bob");
2  if (person != null) {
3      person.updateAccessTime();
4  }
5  String name = person.getName();
 
在這個例子中,如果第 1行的Map不包括一個名爲“bob”的人,那麼在第 5 行詢問person的名字時就會出現 null指針異常。因爲 FindBugs不知道 map是否包含“bob”,所以它將第 5行標記爲可能 null指針異常。
檢測器:初始化之前讀取字段
這個檢測器尋找在構造函數中初始化之前被讀取的字段。這個錯誤通常是——儘管不總是如此——由使用字段名而不是構造函數參數引起的,如清單 3 所示:


清單 3.在構造函數中讀取未初始化的字段
1  public class Thing {
2      private List actions;
3      public Thing(String startingActions) {
4          StringTokenizer tokenizer = new StringTokenizer(startingActions);
5          while (tokenizer.hasMoreTokens()) {
6              actions.add(tokenizer.nextToken());
7          }  
8      }
9  }
在這個例子中,第 6行將產生一個 null指針異常,因爲變量actions還沒有初始化。
這些例子只是 FindBugs所發現的問題種類的一小部分(更多信息請參閱參考資料)。在撰寫本文時,FindBugs提供總共35個檢測器。
開始使用 FindBugs
要運行 FindBugs,需要一個版本 1.4或者更高的 Java Development KitJDK),儘管它可以分析由老的 JDK創建的類文件。要做的第一件事是下載並安裝最新發布的 FindBugs——當前是 0.7.1(請參閱參考資料)。幸運的是,下載和安全是相當簡單的。在下載了 zip或者 tar文件後,將它解壓縮到所選的目錄中。就是這樣了——安裝就完成了。
安裝完後,對一個示例類運行它。就像一般文章中的情況,我將針對 Windows用戶進行講解,並假定那些 Unix信仰者可以熟練地轉化這些內容並跟進。打開命令行提示符號並進入 FindBugs的安裝目錄。對我來說,這是 C:/apps/FindBugs-0.7.3
 FindBugs主目錄中,有幾個值得注意的目錄。文檔在 doc目錄中,但是對我們來說更重要的是,bin目錄包含了運行FindBugs的批處理文件,這使我們進入下一部分。
運行 FindBugs
像如今的大多數數工具一樣,可以以多種方式運行 FindBugs—— GUI、從命令行、使用 Ant、作爲 Eclipse插件程序和使用 Maven。我將簡要提及從 GUI運行 FindBugs,但是重點放在用 Ant和命令行運行它。部分原因是由於 GUI沒有提供命令行的所有選項。例如,當前不能指定要加入的過濾器或者在 UI中排除特定的類。但是更重要的原因是我認爲FindBugs最好作爲編譯的集成部分使用,而 UI不屬於自動編譯。
使用 FindBugs UI
使用 FindBugs UI很直觀,但是有幾點值得說明。如圖 1所示,使用 FindBugs UI的一個好處是對每一個檢測到的問題提供了說明。圖 1顯示了缺陷Naked notify in method的說明。對每一種缺陷模式提供了類似的說明,在第一次熟悉這種工具時這是很有用的。窗口下面的 Source code選項卡也同樣有用。如果告訴 FindBugs在什麼地方尋找代碼,它就會在轉換到相應的選項卡時突出顯示有問題的那一行。
值得一提的還有在將 FinBugs作爲 Ant任務或者在命令行中運行 FindBugs時,選擇xml作爲ouput選項,可以將上一次運行的結果裝載到 UI 中。這樣做是同時利用基於命令行的工具和 UI工具的優點的一個很好的方法。
 FindBugs作爲 Ant任務運行
讓我們看一下如何在 Ant編譯腳本中使用 FindBugs。首先將 FindBugs Ant任務拷貝到 Ant lib目錄中,這樣 Ant就知道新的任務。將 FIND_BUGS_HOME/lib/FindBugs-ant.jar拷貝到 ANT_HOME/lib
現在看看在編譯腳本中要加入什麼才能使用 FindBugs任務。因爲 FindBugs是一個自定義任務,將需要使用taskdef任務以使 Ant知道裝載哪一個類。通過在編譯文件中加入以下一行做到這一點:
<taskdef name="FindBugs" classname="edu.umd.cs.FindBugs.anttask.FindBugsTask"/>
 
在定義了taskdef後,可以用它的名字FindBugs引用它。下一步要在編譯中加入使用新任務的目標,如清單 4 所示:


清單 4.創建 FindBugs目錄
1  <target name="FindBugs" depends="compile">
2      <FindBugs home="${FindBugs.home}" output="xml" outputFile="jedit-output.xml">
3          <class location="c:/apps/JEdit4.1/jedit.jar" />
4          <auxClasspath path="${basedir}/lib/Regex.jar" />
5          <sourcePath path="c:/tempcbg/jedit" />
6      </FindBugs>
7  </target>
 
讓我們更詳細地分析這段代碼中所發生的過程。
 1行:注意target取決於編譯。一定要記住處理的是類文件而是源文件,這樣使target對應於編譯目標保證了 FindBugs可在最新的類文件運行。FindBugs可以靈活地接受多種輸入,包括一組類文件、JAR文件、或者一組目錄。
 2行:必須指定包含 FindBugs的目錄,我是用 Ant的一個屬性完成的,像這樣:
<property name="FindBugs.home" value="C:/apps/FindBugs-0.7.3" />
 
可選屬性output指定 FindBugs的結果使用的輸出格式。可能的值有xmltext或者emacs。如果沒有指定outputFile,那麼FindBugs 會使用標準輸出。如前所述,XML格式有可以在 UI中觀看的額外好處。
 3行:class元素用於指定要 FindBugs分析哪些 JAR、類文件或者目錄。分析多個 JAR或者類文件時,要爲每一個文件指定一個單獨的class元素。除非加入了projectFile元素,否則需要class元素。更多細節請參閱 FindBugs 手冊。
 4行:用嵌套元素auxClasspath列出應用程序的依賴性。這些是應用程序需要但是不希望 FindBugs 分析的類。如果沒有列出應用程序的依賴關係,那麼 FindBugs仍然會儘可能地分析類,但是在找不到一個缺少的類時,它會抱怨。與class元素一樣,可以在 FindBugs元素中指定多個auxClasspath元素。auxClasspath元素是可選的。
 5行:如果指定了sourcePath元素,那麼path屬性應當表明一個包含應用程序源代碼的目錄。指定目錄使 FindBugs 可以在 GUI中查看 XML結果時突出顯示出錯的源代碼。這個元素是可選的。
上面就是基本內容了。讓我們提前幾個星期。
您已經將 FindBugs引入到了團隊中,並運行它作爲您的每小時/每晚編譯過程的一部分。當團隊越來越熟悉這個工具時,出於某些原因,您決定所檢測到的一些缺陷對於團隊來說不重要。也許您不關心一些類是否返回可能被惡意修改的對象——也許,像 JEdit,有一個真正需要的(honest-to-goodness)、合法的理由調用System.gc()
總是可以選擇關閉特定的檢測器。在更細化的水平上,可以在指定的一組類甚至是方法中查找問題時,排除某些檢測器。FindBugs提供了這種細化的控制,可以排除或者包含過濾器。當前只有用命令行或者 Ant啓動的 FindBugs中支持排除和包含過濾器。正如其名字所表明的,使用排除過濾器來排除對某些缺陷的報告。較爲少見但仍然有用的是,包含過濾器只能用於報告指定的缺陷。過濾器是在一個 XML文件中定義的。可以在命令行中用一個排除或者包含開關、或者在 Ant編譯文件中用excludeFilterincludeFilter指定它們。在下面的例子中,假定使用排除開關。還要注意在下面的討論中,我對 “bugcode”“bug”“detector”的使用具有某種程度的互換性。
可以有不同的方式定義過濾器:
  • 匹配一個類的過濾器。可以用這些過濾器忽略在特定類中發現的所有問題。
  • 匹配一個類中特定缺陷代碼(bugcode)的過濾器。可以用這些過濾器忽略在特定類中發現的一些缺陷。
  • 匹配一組缺陷的過濾器。可以用這些過濾器忽略所分析的所有類中的一組缺陷。
  • 匹配所分析的一個類中的某些方法的過濾器。可以用這些過濾器忽略在一個類中的一組方法中發現的所有缺陷。
  • 匹配在所分析的一個類中的方法中發現的某些缺陷的過濾器。可以用這些過濾器忽略在一組方法中發現的特定缺陷。
知道了這些就可以開始使用了。有關其他定製 FindBugs方法的更多信息,請參閱 FindBugs文檔。知道如何設置編譯文件以後,就讓我們更詳細地分析如何將 FindBugs集成到編譯過程中吧!
 FindBugs集成到編譯過程中
在將 FindBugs集成到編譯過程當中可以有幾種選擇。總是可以在命令行執行 FindBugs,但是您很可能已經使用 Ant進行編譯,所以最自然的方法是使用 FindBugs Ant任務。因爲我們在如何運行 FindBugs一節中討論了使用 FindBugs Ant任務的基本內容,所以現在討論應當將 FindBugs加入到編譯過程中的幾個理由,並討論幾個可能遇到的問題。
爲什麼應該將 FindBugs集成到編譯過程中?
經常問到的第一個問題是爲什麼要將 FindBugs加入到編譯過程中?雖然有大量理由,最明顯的回答是要保證儘可能早地在進行編譯時發現問題。當團隊擴大,並且不可避免地在項目中加入更多新開發人員時,FindBugs可以作爲一個安全網,檢測出已經識別的缺陷模式。我想重申在一篇 FindBugs論文中表述的一些觀點。如果讓一定數量的開發人員共同工作,那麼在代碼中就會出現缺陷。像 FindBugs這樣的工具當然不會找出所有的缺陷,但是它們會幫助找出其中的部分。現在找出部分比客戶在以後找到它們要好——特別是當將 FindBugs結合到編譯過程中的成本是如此低時。
一旦確定了加入哪些過濾器和類,運行 FindBugs就沒什麼成本了,而帶來的好處就是它會檢測出新缺陷。如果編寫特定於應用程序的檢測器,則這個好處可能更大。
重要的是要認識到這種成本/效益分析只有在不生成大量誤檢時纔有效。換句話說,如果在每次編譯時,不能簡單地確定是否引入了新的缺陷,那麼這個工具的價值就會被抵消。分析越自動化越好。如果修復缺陷意味着必須吃力地分析檢測出的大量不相干的缺陷,那麼您就不會經常使用它,或者至少不會很好地使用它。
確定不關心哪些問題並從編譯中排除它們。也可以挑出確實關注的一小部分檢測器並只運行它們。另一種選擇是從個別的類中排除一組檢測器,但是其他的類不排除。FindBugs提供了使用過濾器的極大靈活性,這可幫助生成對團隊有意義的結果,由此我們進入下一節。
確定用 FindBugs的結果做什麼
可能看來很顯然,但是您想不到我參與的團隊中有多少加入了類似 FindBugs這樣的工具而沒有真正利用它。讓我們更深入地探討這個問題——用結果做什麼?明確回答這個問題是困難的,因爲這與團隊的組織方式、如何處理代碼所有權問題等有很大關係。不過,下面是一些指導:
  • 可以考慮將 FindBugs結果加入到源代碼管理(SCM)系統中。一般的經驗做法是不將編譯工件(artifact)放到SCM 系統中。不過,在這種特定情況下,打破這個規則可能是正確的,因爲它使您可以監視代碼質量隨時間的變化。
  • 可以選擇將 XML結果轉換爲可以發送到團隊的網站上的 HTML報告。轉換可以用 XSL樣式表或者腳本實現。有關例子請查看 FindBugs網站或者郵件列表(請參閱參考資料)。
  •  FindBugs這樣的工具通常會成爲用於敲打團隊或者個人的政治武器。儘量抵制這種做法或者不讓它發生——記住,它只是一個工具,它可以幫助改進代碼的質量。有了這種思想,在下一部分中,我將展示如何編寫自定義缺陷檢測器。
結束語
我鼓勵讀者對自己的代碼試用靜態分析工具,不管是 FindBugsPMD還是其他的。它們是有用的工具,可以找出真正的問題,而 FindBugs是在消除誤檢方面做得最好的工具。此外,它的可插入結構提供了編寫有價值的、特定於應用程序的檢測器的、有意思的測試框架。在本系列的第 2 部分中,我將展示如何編寫自定義檢測器以找出特定於應用程序的問題。
 

詳解eclipse插件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 checkouthttp://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] view plaincopy
  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. }    

[java] view plaincopy
  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. }  

[java] view plaincopy
  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" />  

[xhtml] view plaincopy
  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>  

[xhtml] view plaincopy
  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>  

[xhtml] view plaincopy
  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就可以使用新的規則了 

 

 

其它分析工具

除FingBugs靜態分析工具外,還有PMD和Checkstyle,FingBugs、PMD和Checkstyle三個工具各有不同的特點,聯合使用有助於減少誤報錯誤,提高報告的準確率。

 

這三個工具檢查的側重點各有不同: 

工具

目的

主要檢查內容

FindBugs

基於Bug Patterns概念,查找java bytecode中的潛在bug。在目前版本中,它不檢查java源文件。

主要檢查bytecode中的bug patterns,也允許用戶自定義特定的bug patterns。

PMD

檢查java源文件中的潛在問題。

主要包括:

  -  空try/catch/finally/switch語句塊

 -       未使用的局部變量、參數和private方法

 -       空if/while語句

 -       過於複雜的表達式,如不必要的if語句等

 -       複雜類

CheckStyle

檢查java源文件是否與代碼規範相符

主要包括

 -       Javadoc註釋

 -       命名規範

 -       Headers

 -       Imports

 -       Size衝突和度量,如過長的方法

 -       Whitespace

 -       Modifiers

 -       Blocks

 -       Coding Problems

 -       Class Design

 -       重複代碼

 -       Miscellaneous Checks

 -       Optional Checks

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章