NullAway は、Java コード内のNullPointerException
(NPE) を排除するのに役立つツールです。 NullAway を使用するには、まずフィールド、メソッドのパラメーター、または戻り値がnull
になる可能性があるコード内のどこにでも@Nullable
アノテーションを追加します。これらのアノテーションが与えられると、NullAway は一連の型ベースのローカル チェックを実行して、コード内で逆参照されるポインターがnull
であってはいけないことを確認します。 NullAway は、Kotlin および Swift 言語の型ベースの null 可能性チェック、Java の Checker Framework および Eradicate null チェッカーに似ています。
NullAway は高速です。これは Error Prone のプラグインとして構築されており、コードのすべてのビルドで実行できます。私たちの測定では、NullAway の実行によるビルド時のオーバーヘッドは通常 10% 未満です。 NullAway は実用的でもあります。コード内で考えられるすべての NPE を防ぐわけではありませんが、合理的なアノテーションの負担を課しながら、実稼働環境で観察された NPE のほとんどを捕捉し、大きな「費用対効果」をもたらします。
NullAway では、Error Prone バージョン 2.14.0 以降でコードをビルドする必要があります。 Error Prone の使用を開始する手順とビルド システムとの統合については、Error Prone のドキュメントを参照してください。以下の手順は、Gradle を使用していることを前提としています。他のビルド システムについてはドキュメントを参照してください。
NullAway を Android 以外の Java プロジェクトに統合するには、以下をbuild.gradle
ファイルに追加します。
plugins {
// we assume you are already using the Java plugin
id " net.ltgt.errorprone " version " <plugin version> "
}
dependencies {
errorprone " com.uber.nullaway:nullaway:<NullAway version> "
// Some source of nullability annotations; JSpecify recommended,
// but others supported as well.
api " org.jspecify:jspecify:1.0.0 "
errorprone " com.google.errorprone:error_prone_core:<Error Prone version> "
}
import net.ltgt.gradle.errorprone.CheckSeverity
tasks . withType( JavaCompile ) {
options . errorprone {
check( " NullAway " , CheckSeverity . ERROR )
option( " NullAway:AnnotatedPackages " , " com.uber " )
}
// Include to disable NullAway on test code
if (name . toLowerCase() . contains( " test " )) {
options . errorprone {
disable( " NullAway " )
}
}
}
このスクリプトを段階的に見てみましょう。 plugins
セクションでは、Error Prone 統合用の Gradle Error Prone プラグインを取り込みます。
dependencies
では、最初のerrorprone
行で NullAway がロードされ、 api
行で適切な null 可能性アノテーション ( org.jspecify.annotations.Nullable
など) を提供する JSpecify ライブラリがロードされます。 NullAway では、任意の@Nullable
アノテーションを使用できるため、たとえば、AndroidX アノテーション ライブラリまたは JetBrains アノテーションの@Nullable
も問題ありません。 2 番目のerrorprone
行は、使用される Error Prone のバージョンを設定します。
最後に、 tasks.withType(JavaCompile)
セクションで、いくつかの構成オプションを NullAway に渡します。最初のcheck("NullAway", CheckSeverity.ERROR)
NullAway の問題をエラー レベルに設定します (これは、標準の Error Prone 引数-Xep:NullAway:ERROR
と同等です)。デフォルトでは、NullAway は警告を発行します。次に、 option("NullAway:AnnotatedPackages", "com.uber")
( -XepOpt:NullAway:AnnotatedPackages=com.uber
標準の Error Prone 引数に相当) は、 com.uber
名前空間の下のパッケージ内のソース コードを次のようにする必要があることを NullAway に伝えます。 null 逆参照と@Nullable
注釈の適切な使用法がチェックされ、これらのパッケージ内のクラス ファイルには@Nullable
が正しく使用されていると想定される必要があります。 (詳細についてはドキュメントを参照してください)。 NullAway では、注釈付きコードと注釈なしコードを区別するために、少なくともAnnotatedPackages
構成引数を実行する必要があります。他の便利な構成オプションについては、構成ドキュメントを参照してください。 NullAway オプションの構成をさらに簡単にするには、Gradle NullAway プラグインを使用します。最後に、必要に応じてテスト コードで NullAway を無効にする方法を示します。
Error Prone が報告するすべての問題、特に (警告ではなく) エラーとして報告される問題に対処することをお勧めします。ただし、他のエラー傾向チェックを実行せずに NullAway を試したい場合は、 options.errorprone.disableAllChecks
(NullAway 固有の引数の前に"-XepDisableAllChecks"
コンパイラに渡すのと同等) を使用できます。
Gradle Error Prone Plugin のバージョン 3.0.0 以降は Android をサポートしなくなりました。したがって、このプラグインの最新バージョンを使用している場合は、Error Prone と NullAway を実行するためにさらに構成を追加する必要があります。サンプル アプリのbuild.gradle
ファイルはこれを行う 1 つの方法を示していますが、Android プロジェクトでは調整が必要な場合があります。あるいは、Gradle Error Prone Plugin の 2.x バージョンは引き続き Android をサポートしており、プロジェクトで引き続き動作する可能性があります。
さらに、Java 構成と比較して、JSpecify 依存関係を削除できます。代わりに、AndroidX アノテーション ライブラリのandroidx.annotation.Nullable
アノテーションを使用できます。
Dagger や AutoValue などの一部の注釈プロセッサは、独自のコードと同じパッケージ名前空間にコードを生成します。この生成されたコード内のエラーによりビルドがブロックされるため、上で提案したように NullAway をERROR
レベルに設定すると問題が発生する可能性があります。現在、この問題に対する最善の解決策は、Error Prone 2.1.3 で追加された-XepExcludedPaths
オプションを使用して、生成されたコードで Error Prone を完全に無効にすることです (ここに文書化されており、Gradle ではoptions.errorprone.excludedPaths=
を使用します)。使用するには、生成されたコードがどのディレクトリに含まれているかを確認し、そのディレクトリを除外パス正規表現に追加します。
Dagger ユーザーへの注意: Dagger バージョン 2.12 より古い場合、NullAway との相互作用が不適切になる可能性があります。ここを参照してください。この問題を解決するには、Dagger 2.12 に更新してください。
上記の他のアノテーション プロセッサとは異なり、Lombok は処理するコードのメモリ内 AST を変更します。これが、Error Prone、ひいては NullAway との多数の非互換性の原因となります。
Lombok で NullAway を使用することは特にお勧めしません。ただし、NullAway は一般的な Lombok アノテーションに関する知識をエンコードしており、ベストエフォート型の互換性を確保するよう努めています。特に、 @lombok.Builder
クラスや@Data
クラスなどの一般的な使用法をサポートする必要があります。
NullAway がインメモリ Java AST 内で Lombok 生成コードを正常に検出するには、次の構成オプションを該当するlombok.config
ファイルの一部として Lombok に渡す必要があります。
lombok.addLombokGeneratedAnnotation = true
これにより、Lombok は生成するメソッド/クラスに@lombok.Generated
を追加します。 NullAway は、この生成されたコードの実装を無視し (つまり、チェックせず)、注釈なしとして扱います。
簡単なコード例で NullAway がどのように動作するかを見てみましょう。
static void log ( Object x ) {
System . out . println ( x . toString ());
}
static void foo () {
log ( null );
}
このコードにはバグがあります。foo foo()
が呼び出されると、後続のlog()
の呼び出しは NPE で失敗します。 NullAway サンプル アプリでこのエラーを確認するには、次のコマンドを実行します。
cp sample/src/main/java/com/uber/mylib/MyClass.java.buggy sample/src/main/java/com/uber/mylib/MyClass.java
./gradlew build
デフォルトでは、NullAway はすべてのメソッド パラメータ、戻り値、およびフィールドが非null であると想定します。つまり、 null
値を割り当てることはできません。上記のコードでは、 log()
のx
パラメーターは null ではないと想定されています。したがって、NullAway は次のエラーを報告します。
warning: [NullAway] passing @Nullable parameter 'null' where @NonNull is required
log(null);
^
@Nullable
アノテーションを付けてnull
log()
に渡すことを許可することで、このエラーを修正できます。
static void log ( @ Nullable Object x ) {
System . out . println ( x . toString ());
}
このアノテーションを使用して、NullAway は null 逆参照の可能性を指摘します。
warning: [NullAway] dereferenced expression x is @Nullable
System.out.println(x.toString());
^
この警告は、null チェックを追加することで修正できます。
static void log ( @ Nullable Object x ) {
if ( x != null ) {
System . out . println ( x . toString ());
}
}
この変更により、すべての NullAway 警告が修正されました。
NullAway のチェック、エラー メッセージ、制限事項の詳細については、詳細ガイドを参照してください。
NullAway の使用方法について質問がある場合は、お気軽に GitHub のイシューを開いてください。または、NullAway Discord サーバーに参加して、そこで質問することもできます。
ぜひ NullAway に貢献してください。プル リクエストを作成すると、Uber コントリビューター ライセンス契約への署名が求められることに注意してください。
NullAway は MIT ライセンスに基づいてライセンスされています。詳細については、LICENSE.txt ファイルを参照してください。