可変長固定長

IT関係の話題が中心

FindBugsの導入と使い方、AntタスクによるFindBugsの実行

java開発でたびたび登場するソースコード静的チェックツールであるFindBugs

FindBugsの導入と使い方、AntタスクによるFindBugsの実行方法を簡単にご紹介。

 

 

目次

 

 

 

動作環境

FindBugs の動作環境は以下の通りです。

  • プラットフォーム非依存(LinuxWindowsMac
  • JDK 1.5 以降
  • 512 MB 以上のメモリ空き容量

 

巨大なプロジェクトを解析するためには、それより多くのメモリが必要とされることがあります。

 

と、ユーザーガイドには記載されているとおり、数十万ステップのプロジェクトを解析するには1G以上のメモリを必要とすることもあります。

 

 

FindBugsをダウンロード

FindBugs のバイナリをダウンロードします。

現在の最新バージョンである 3.0.1 を以下のURLからダウンロードします。

https://sourceforge.net/projects/findbugs/files/findbugs/3.0.1/findbugs-3.0.1.zip/download

ダウンロードされたファイルは「findbugs-3.0.1.zip」です。

 

ダウンロードしたバイナリを展開します。

展開されたファイルは findbugs-[バージョン番号] というフォルダを作成します。

 

今回は FindBugs の展開先を環境変数 %FINDBUGS_HOME% としてコマンドなどを例示します。

 

 

FindBugs の実行

FindBugsGUIでも利用することができますが、多くの場合はスクリプト処理で解析レポートを出力することが多いと思います。もっともベーシックな使い方は次の構文です。

 

> java [JVM 引数] -jar %FINDBUGS_HOME%/lib/findbugs.jar オプション…

 

このコマンドは FindBugs の本体である「$FINDBUGS_HOME/lib/findbugs.jar」を直接実行する方法です。実際にやってみましょう。ここでは HelloWorld アプリケーションに対して FindBugs を実行してみます。

 

public class Hello {
public static void main(String args) {
String msg = null;
//msg = "Hello, World!"; /* ここにバグ */
say(msg);
}
public static void say(Object o) {
System.out.println(o.toString());
}
}

コンパイルします。
> javac Hello.java

FindBugs を実行します。

> java -jar %FINDBUGS_HOME%\lib\findbugs.jar -textui -html -output findbugs.html Hello.class

 

findbugs.jar に対して、 Hello.java ではなく Hello.class を解析対象として引数に与えていることに注意してください。ソースコードではなく、バイトコードに対して静的解析を実施するため、 FindBugs では強力なバグチェックツールとなっています。


オプションの説明は以下の通りです。

-textui: コマンドラインインタフェースを起動します。
-html: HTML 出力が生成されます。
-output ファイル名(指定したファイルに出力結果が作成されます。)

 

 

上記コマンドでは、 Hello.class を解析し、 findbugs.html という名前で解析結果のレポートを出力しています。

 

 

解析レポート(HTMLファイル)

解析結果のレポートは HTML ファイルで出力されるため、通常のブラウザで閲覧が可能です。 Hello.class の解析結果のサンプルは次のような内容が出力されます。

 

f:id:gumt:20170109173728p:plain

 

この HTML ファイルのレポートは UTF-8 の文字コードで出力されるので、もしブラウザでみたときに文字化けしていたら、ブラウザのエンコード設定を UTF-8 に変更してみてください。

 

 


解析結果からソースコードを修正

 

解析結果では「NP_NULL_PARAM_DEREF_NONVIRTUAL: 非 null パラメータに null を渡している非仮想メソッドの呼び出し」というバグパターンが検出されていました。実際、この Hello.class を実行すると NullPointerException が発生します。

 

> java Hello
Exception in thread "main" java.lang.NullPointerException
at Hello.say(Hello.java:8)
at Hello.main(Hello.java:5)

main メソッドの5行目で実行している say メソッド(8行目)で実行時エラーが起きていることがわかります。findbugs のレポートでも「該当箇所 Hello.java:[line 5]" 引数 1 は間違いなく null ですが、null であってはなりません」と出力されています。

 

 

したがって、以下のようにソースコードを修正します。


public class Hello {
public static void main(String args) {
String msg = null;
msg = "Hello, World!"; /* バグを修正 */
say(msg);
}
public static void say(Object o) {
System.out.println(o.toString());
}
}

 

無事、 Hello,World! と出力され、 findbugs で再度解析するとバグは検出されなくなりました。

> java Hello
Hello, World!

 

 

Ant タスクによる findbugs の実行方法

これまで findbugs.jar を利用した最もベーシックな findbugs の使い方を説明しました。 findbugs.jar による java ソースコードの静的解析は簡単ではありますが、通常 java プロジェクトは複数のファイルから構成されるため、一つ一つコマンドを打っていくには現実的ではありません。

 

多くの場合はビルドツールを利用します。java でビルドツールといえば最もメジャーなプロダクトは Ant であり、findbugs も Ant タスクと連携して実行することができます。

 

 

Ant のダウンロード

以下の URL から「apache-ant-1.9.7-bin.zip」をダウンロードします。
http://ftp.jaist.ac.jp/pub/apache/ant/binaries/apache-ant-1.9.7-bin.zip

 

ダウンロードした Zip ファイルは任意のフォルダに解凍します。

 

 

Ant のインストール

Ant のインストールは環境設定を追加するだけで利用可能になります。

 

  • ANT_HOME 

Ant がインストールされているディレクトリを指定

  • JAVA_HOME 

JDK がインストールされているディレクトリを指定

  • PATH 

Ant の実行ファイル(bin フォルダ)の場所を追加

 

 

設定が終わればコマンドプロンプトで「ant」と打ってみましょう。

> ant
Buildfile: build.xml does not exist!
Build failed

 

上のように build.xml がないのでビルドができませんとメッセージがでてきたらインストールは成功しています。Ant はカレントディレクトリ内の build.xml ファイルをもとにビルドを実行します。この build.xml は後述します。

 

 

findbugs と ant の連携

findbugs と ant の連携するためには、$FINDBUGS_HOME/lib/findbugs-ant.jar  を ant を解凍したディレクトリの lib ディレクトリにコピーするだけです。

 

 

Ant タスク(build.xml)の作成

Ant でビルドするためには build.xml が必要です。build.xml は Ant でビルドを実行するために定義する XML ファイルです。以下の Ant ユーザーマニュアルを参考に build.xml を作成します。

http://www.jajakarta.org/ant/ant-1.6.1/docs/ja/manual/index.html

 

<?xml version="1.0" encoding="Shift_JIS" ?>
<project name="MyProject" default="dist" basedir=".">
<description>
簡単なビルドファイルの例
</description>
<!-- このビルド用のグローバルプロパティを設定する -->
<property name="src" location="src"/>
<property name="build" location="build"/>
<property name="dist" location="dist"/>

<target name="init">
<!-- タイムスタンプを作成する -->
<tstamp/>
<!-- コンパイルで使用するビルドディレクトリ構造を作成する -->
<mkdir dir="${build}"/>
</target>

<target name="compile" depends="init"
description="ソースをコンパイルする" >
<!-- ${src}から${build}に、Javaコードをコンパイルする -->
<javac srcdir="${src}" destdir="${build}"/>
</target>

<target name="dist" depends="compile"
description="配布物を生成する" >
<!-- distributionディレクトリを作成する -->
<mkdir dir="${dist}/lib"/>

<!-- ${build}の中のすべてのファイルをMyProject-${DSTAMP}.jarファイルに格納する -->
<jar jarfile="${dist}/lib/MyProject-${DSTAMP}.jar" basedir="${build}"/>
</target>

<target name="clean"
description="クリーンアップ" >
<!-- ${build}と${dist}ディレクトリツリーを削除する -->

<delete dir="${build}"/>
<delete dir="${dist}"/>
</target>
</project>

 

※ユーザーマニュアルにも記載されていますが、 build.xml 内に日本語を記載する場合は Shift-JIS で保存しましょう。

 

[訳注: ビルドファイル中に日本語を入力するには、ファイルの最初に<?xml version="1.0" encoding="Shift_JIS"?>のように使用する文字コードを指定する必要があります。そうしないと、デフォルトの UTF-8 コードであるとみなされ、BUILD FAILED Error reading project file: invalid byte 1 of 1-byte UTF-8 sequence (0xb4) のようなエラーメッセージが表示されることがあります。]

 

 

上にも述べましたが build.xml はプロジェクトのカレントディレクトリに配置します。今回は TestProject というディレクトリを作成し、その直下に build.xml を配置します。

 

また、TestProject の直下には src ディレクトリを作成して、java ソースファイルを配置してください。これで Ant を実行する環境が整いました。

 

 

Ant タスクの実行

デフォルトの設定のままビルドします。
> ant

 

 

すると、build フォルダ、dist フォルダが作成され、それぞれ class ファイルと jar ファイルが生成されていると思います。これでビルドが完了です。

 

 

findbugs ターゲットを追加

Ant タスクに findbugs ターゲットを追加して、findbugs による静的解析を Ant から実行できるようにしましょう。

 

 

<?xml version="1.0" encoding="Shift_JIS" ?>
<project name="MyProject" default="dist" basedir=".">

<!-- ★findbugs のクラスを設定 -->
<taskdef name="findbugs" classname="edu.umd.cs.findbugs.anttask.FindBugsTask"/>

<description>
簡単なビルドファイルの例
</description>
<!-- このビルド用のグローバルプロパティを設定する -->
<property name="src" location="src"/>
<property name="build" location="build"/>
<property name="dist" location="dist"/>

<!-- ★findbugs ホームディレクトリを指定 -->
<property name="findbugs.home" location="C:\Dev\findbugs-3.0.1"/>

<target name="init">
<!-- タイムスタンプを作成する -->
<tstamp/>
<!-- コンパイルで使用するビルドディレクトリ構造を作成する -->
<mkdir dir="${build}"/>
</target>

<target name="compile" depends="init"
description="ソースをコンパイルする" >
<!-- ${src}から${build}に、Javaコードをコンパイルする -->
<javac srcdir="${src}" destdir="${build}"/>
</target>

<target name="dist" depends="compile"
description="配布物を生成する" >
<!-- distributionディレクトリを作成する -->
<mkdir dir="${dist}/lib"/>

<!-- ${build}の中のすべてのファイルをMyProject-${DSTAMP}.jarファイルに格納する -->
<jar jarfile="${dist}/lib/MyProject-${DSTAMP}.jar" basedir="${build}"/>
</target>

<target name="clean"
description="クリーンアップ" >
<!-- ${build}と${dist}ディレクトリツリーを削除する -->

<delete dir="${build}"/>
<delete dir="${dist}"/>
</target>

<!-- ★findBugs ターゲットを作る -->
<target name="findbugs" depends="compile">
<findbugs home="${findbugs.home}" output="html" outputFile="findbugs.html" >
<sourcePath path="${src}" />
<class location="${build}" />
</findbugs>
</target>
</project>

 

 

 

デフォルトの build.xml に上記★が付いた部分を追加します。いろいろと設定は可能ですが、とりあえず動かすためには少しの追加で大丈夫です。findbugs.home については、findbugs をインストールしたディレクトリを指定します。

 

細かい設定がしたい場合はユーザーマニュアルを確認しましょう。

http://findbugs.sourceforge.net/ja/manual/anttask.html

 

 


Ant タスクで findbugs を実行

さっそく Ant を実行します。


> ant findbugs

 

ant に加えて findbugs ターゲットを指定します。これによってコンパイルと同時に findbugs による静的解析結果を HTML ファイルに出力してくれるようになります。

 

もちろん複数ソースファイルがあれば複数のソースファイルに対してコンパイルと同時にバグ解析を実施してくれます。

 

 

 

開発のプロが教える標準FindBugs完全解説―Javaバグパターンの詳細と対策 (デベロッパー・ツール・シリーズ)

開発のプロが教える標準FindBugs完全解説―Javaバグパターンの詳細と対策 (デベロッパー・ツール・シリーズ)