JSR 305: Annotations for Software Defect Detection

前回に引き続き、今回も将来的にJava SEに取り込まれる可能性のあるアノテーション関連のJSRを取り上げたいと思う。今回紹介するのは、Javaプログラムのバグ退治をサポートするアノテーションの標準セットとなる「JSR 305: Annotations for Software Defect Detection」だ。

現在、Javaプログラムのバグを探すにはFindBugsIntelliJなどに代表されるバグ検証ツールを利用するのが一般的である。これらのツールを利用することで、バグの原因となりやすいコードパターンや無意味な処理を行っている箇所などを開発時に容易に発見することができる。

JSR 305では、こういったバグ検証をサポートするアノテーションの標準セットを提供する。たとえばNullチェックを行うアノテーションや、メソッドの戻り値の検証、並行性の誤りチェックなどを行うアノテーションなどの導入が検討されている。

FindBugsやIntelliJでは、現時点ですでにこのようなアノテーションの数々が用意されており、各ツールによるバグの検証に利用することができる。ただしそれらは各々独自に開発されたものであるため、他ツールとの互換性は考慮されていない。JSR-305ではこれらのアノテーションの仕様を標準化することで、各ツール間の互換性を確保する狙いがある。また、現時点では検証コードを挿入することが困難な部分も、新たなアノテーションによって検証が可能になるという効果も期待されている。

JSR 305で用意されるアノテーション

JSR 305のスペックリードはFindBugsプロジェクトの創立者であるWilliam Pugh氏が務め、エキスパートグループにはIntelliJをリリースしているJetBrainsなどが参加している。この面子を見てもわかるように、JSR 305の仕様はFindBugsやIntelliJの影響を強く受けており、まずはこれらのツールで提供されているアノテーションと同等のものが用意される予定である。

JSR 305の仕様に間するディスカッションは、Google Groups内にあるJSR 305グループで行われている。それによれば、現在のところ下記のようなアノテーションの採用が検討されている。

  • @Nonnull: nullを許容しない
  • @Nullable: nullを許容する
  • @CheckForNull: nullになる可能性を考慮してチェックを促す
  • @Nonnegative: 負数を許容しない
  • @Signed: 符合付き数値のみ許可
  • @CheckForNegative: 負数になる可能性を考慮してチェックを促す
  • @Positive: 正数のみ許可
  • @CheckForNonpositive: 正数で無い可能性を考慮してチェックを促す
  • @CheckReturnValue: メソッドの戻り値をチェック
  • @Nls: 自然言語の文字列のみ許可
  • @NonNls: 自然言語でない文字列のみ許可
  • @Syntax: シンタックスを指定(たとえば"JavaScript"など)
  • @Pattern: 文字列のパターンを指定
  • @RegEx: 正規表現の文字列のみ許可
  • @ResultSetType: ResultSetのタイプを示す値のみ許可
  • @ResultSetConcurrency: ResultSetの並行処理モードを示す値のみ許可
  • @ResultSetHoldability: ResultSetの保持機能モードを示す値のみ許可
  • @InjectionAnnotation: あるアノテーションがリソースインジェクションのためのものであることを示す

実際にどのようなアノテーションがどのような実装で採用されるのかは現在も活発に議論されている最中であり、ここで挙げたものがすべてというわけでもない。上記以外の候補としては、たとえば並列プログラミングをサポートする@GuardedBy、@ThreadSafe、@NotThreadSafe、@Immutableなどがある。これらFindBugsでサポートされているアノテーションの一部だ。あるアノテーションが単体テスト用のものであることを示す、@TestAnnotationアノテーションなどの提案もある。そのほかにも独自のアイデアがある場合には、グループに参加して提案してみるといいだろう。

FingBugsのアノテーションを試す

それでは、実際にJSR 308で用意されるアノテーションを使ってどのようなことができるのかを知るために、同JSRのモデルとなっているFindBugsで提供されるアノテーションを試してみよう。

FindBugsはここからダウンロードできる。配布ファイルのlibディレクトリにあるannotation.jarに、FindBugsで提供されるアノテーションが含まれている。どのようなアノテーションが使えるかはAPIドキュメントを参照のこと。ここでは、JSR 305にも同様の機能のものが採用された@NonNull、@Nullable、@CheckForNullの3つを使ってリスト1のようなプログラムを作ってみた。

リスト1 FindBugsAnnotationSample.java - FingBugsのnullチェック用アノテーションの使用例

package samples;

import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;
import edu.umd.cs.findbugs.annotations.CheckForNull;

public class FindBugsAnnotationSample {
    @NonNull
    public static String nonNullMethod() {
        return null;
    }

    @CheckForNull
    public static String checkForNullMethod() {
        return null;
    }

    @Nullable 
    public static String nullableMethod() {
        return null;
    }

    public static void main(String[] args) {   
        String str;
        str = nonNullMethod().trim();
        System.out.println(str);
        str = checkForNullMethod().trim();
        System.out.println(str);
        str = nullableMethod().trim();
        System.out.println(str);
    }
}

これをコンパイルして、図1のようにJARファイルにまとめる。そしてFindBugsを用いてバグ検証してみると、図2のように2つのバグが報告される。

サンプルプログラムをJARファイルにまとめる

FindBugsAnnotationSample.javaの検証結果

1つ目はnonNullMethod()メソッドがnullを返そうとしていることの警告で、@NonNullアノテーションが効いていることがわかる。2つ目はcheckForNullMethod()メソッドから返されたオブジェクトに対してtrim()を実行しようとしたことに対する警告で、これは@CheckForNullによってnullチェックを促されていることによる。nullableMethod()メソッドは@Nullableなのでとくに警告は受けていない。バグ検証のためのアノテーションの役割がわかっていただけただろうか。

ちなみに、Google CodeにもJSR 305用のプロジェクトページが用意されており、そこではSubversionリポジトリにおいて参照実装のソースコードが公開されている。

スペックリードのWilliam Pugh氏によれば、今後は夏過ぎごろまでに仕様に関する議論をいったんまとめ、叩き台となる実装の作成を行う予定だという。JSR 305は今のところJava SE 7の候補には入っていないが、エキスパートグループは最終的にこのJSRがJava SEに統合されることを目指している。その場合、前回紹介したJSR 308との互換性なども気になるところだ。