Checkerフレームワーク-Java用のプラグイン可能なタイプシステム
1. 概要
Java 8リリース以降、いわゆるPluggable Type Systemsを使用してプログラムをコンパイルできるようになりました。これにより、コンパイラーによって適用されるチェックよりも厳密なチェックを適用できます。
使用可能ないくつかのPluggable Type Systemsによって提供される注釈のみを使用する必要があります。
この簡単な記事では、ワシントン大学の厚意により、the Checker Frameworkについて説明します。
2. メーベン
チェッカーフレームワークの使用を開始するには、最初にそれをpom.xml:に追加する必要があります
org.checkerframework
checker-qual
2.3.2
org.checkerframework
checker
2.3.2
org.checkerframework
jdk8
2.3.2
ライブラリの最新バージョンはMaven Centralで確認できます。
最初の2つの依存関係にはThe Checker Frameworkのコードが含まれ、後者はJava 8クラスのカスタムバージョンであり、すべてのタイプがThe Checker Frameworkの開発者によって適切に注釈が付けられています。
次に、The Checker Frameworkをプラグ可能なType Systemとして使用するために、maven-compiler-pluginを適切に微調整する必要があります。
maven-compiler-plugin
3.6.1
1.8
1.8
10000
10000
org.checkerframework.checker.nullness.NullnessChecker
org.checkerframework.checker.interning.InterningChecker
org.checkerframework.checker.fenum.FenumChecker
org.checkerframework.checker.formatter.FormatterChecker
-AprintErrorStack
-Awarns
ここでの要点は、<annotationProcessors>タグの内容です。 ここでは、ソースに対して実行するすべてのチェッカーをリストしました。
3. NullPointerExceptionsの回避
The Checker Frameworkが役立つ最初のシナリオは、NullPoinerExceptionが発生する可能性のあるコードを特定することです。
private static int countArgs(@NonNull String[] args) {
return args.length;
}
public static void main(@Nullable String[] args) {
System.out.println(countArgs(args));
}
上記の例では、countArgs()のargs引数がnullであってはならないことを@NonNullアノテーションで宣言しました。
この制約に関係なく、main()では、@Nullableでアノテーションが付けられているため、実際にはnullになる可能性のある引数を渡すメソッドを呼び出します。
コードをコンパイルすると、The Checker Frameworkは、コード内の何かが間違っている可能性があることを適切に警告します。
[WARNING] /checker-plugin/.../NonNullExample.java:[12,38] [argument.type.incompatible]
incompatible types in argument.
found : null
required: @Initialized @NonNull String @Initialized @NonNull []
4. 列挙型としての定数の適切な使用
列挙のアイテムである一連の定数を使用する場合があります。
一連の国と惑星が必要だとしましょう。 次に、これらのアイテムに@Fenumアノテーションを付けて、同じ「偽の」列挙の一部であるすべての定数をグループ化できます。
static final @Fenum("country") String ITALY = "IT";
static final @Fenum("country") String US = "US";
static final @Fenum("country") String UNITED_KINGDOM = "UK";
static final @Fenum("planet") String MARS = "Mars";
static final @Fenum("planet") String EARTH = "Earth";
static final @Fenum("planet") String VENUS = "Venus";
その後、「planet」であるStringを受け入れるメソッドを記述すると、引数に適切に注釈を付けることができます。
void greetPlanet(@Fenum("planet") String planet){
System.out.println("Hello " + planet);
}
エラーとして、惑星の可能な値として定義されていない文字列を使用してgreetPlanet()を呼び出すことができます。
public static void main(String[] args) {
obj.greetPlanets(US);
}
The Checker Frameworkはエラーを見つけることができます:
[WARNING] /checker-plugin/.../FakeNumExample.java:[29,26] [argument.type.incompatible]
incompatible types in argument.
found : @Fenum("country") String
required: @Fenum("planet") String
5. 正規表現
String変数は、少なくとも1つの一致するグループを持つ正規表現を格納する必要があることがわかっているとします。
the Checker Frameworkを活用して、次のような変数を宣言できます。
@Regex(1) private static String FIND_NUMBERS = "\\d*";
FIND_NUMBERSに割り当てた正規表現には一致するグループがないため、これは明らかに潜在的なエラーです。
実際、the Checker Frameworkは、コンパイル時にエラーについて熱心に通知します。
[WARNING] /checker-plugin/.../RegexExample.java:[7,51] [assignment.type.incompatible]
incompatible types in assignment.
found : @Regex String
required: @Regex(1) String
6. 結論
The Checker Frameworkは、標準のコンパイラを超えてコードの正確性を向上させたい開発者にとって便利なツールです。
コンパイル時に、通常は実行時にのみ検出できるいくつかの一般的なエラーを検出したり、コンパイルエラーを発生させてコンパイルを停止したりすることができます。
この記事で取り上げたものよりもはるかに多くの標準チェックがあります。 The Checker Frameworkの公式マニュアルhereで利用可能なチェックを確認するか、独自に作成してください。
いつものように、このチュートリアルのソースコードは、いくつかの例とともに、over on GitHubにあります。